Каждый объект, зарегистрированный в качестве получателя уведомлений, вы вольны снять с регистрации, прежде чем он прекратит свое существование.
Если вы не сделаете этого, а объект прекратит свое существование и будет разослано уведомление, для получения которого этот объект зарегистрирован, то центр уведомлений попытается отправить соответствующее сообщение данному, уже отсутствующему объекту. В итоге произойдет аварийный отказ в лучшем случае, а в худшем — полный хаос.
Для того чтобы снять объект с регистрации на получение уведомлений, достаточно отправить центру уведомлений сообщение removeObserver:. (С другой стороны, объект можно снять с регистрации на получение только отдельных уведомлений с помощью метода removeObserver: name : object:.) В качестве аргумента observer: соответствующему методу передается объект, который уже не принимает уведомления. Каким должен быть этот объект, зависит, прежде всего, от одного из следующих способов регистрации.
Вызов метода addObserver:...................
В этом случае наблюдатель предоставляется изначально, а следовательно, заранее известен наблюдатель, который требуется снять с регистрации.
Вызов метода addObserverForName:....
В результате вызова метода addObserverForName: . . . возвращается объект маркера наблюдателя, который сохраняется в переменной id (его класс и характер особого значения не имеют). По существу, это наблюдатель, который требуется снять с регистрации.
Самое главное — найти подходящий момент для снятия с регистрации. В качестве запасного варианта можно воспользоваться методом dealloc зарегистрированного экземпляра. Это последнее событие времени действия, посылаемое экземпляру перед тем, как он прекратит свое существование. Если выбрать второй способ снятия с регистрации, воспользовавшись механизмом ARC и методом addObserverForName: . . ., то следует принять во внимание некоторые дополнительные последствия для управления памятью, о которых речь пойдет в главе 12.
Если метод addObserverForName: . . . вызывается многократно из одного и того же класса, то в конечном итоге из центра уведомлений поступает множество маркеров наблюдателя, которые приходится сохранять, чтобы в дальнейшем снять их с регистрации. Если же предполагается снять с регистрации все объекты сразу, то для этой цели можно сохранить их в виде изменяемой коллекции в переменной экземпляра. Так, если имеется переменная
экземпляра _observers типа NSMutableSet, то с самого начала она инициализируется пустым множеством, как показано ниже.
self->_observers = [NSMutableSet set];
Всякий раз, когда регистрация на получение уведомлений производится с помощью блока, результат фиксируется и вводится в множество следующим образом:
Когда же наступает время для снятия с регистрации, то организуется перечисление элементов множества, как показано ниже.
Неудобство организации всей этой процедуры является той ценой, которую приходится платить за преимущества, которые дают блоки при обращении с уведомлениями.
В классе NSNotif icationCenter никакой интроспекции не предоставляется. В частности, к центру уведомлений типа NSNotif icationCenter нельзя обратиться с запросом, чтобы выяснить, какие именно объекты зарегистрированы в нем в качестве получателей уведомлений. На мой взгляд, это серьезный пробел в функциональных возможностях среды Cocoa. Некогда мне пришлось потратить немало времени, чтобы понять, почему один из экземпляров в коде моего приложения не получал уведомление, на которое он был зарегистрирован. Простейшая самодиагностика кода не помогла. Однако в конечном итоге я понял, что в одном забытом мною фрагменте кода наблюдатель преждевременно снимался с регистрации. Из всего сказанного можно сделать следующий вывод: логика постановки и снятия с регистрации должна быть очень простой.