В Cocoa мне нужно удалить объект из получения уведомлений KVO при его освобождении?

Когда я зарегистрировал объект foo для получения уведомлений KVO с другого объекта bar (используя addObserver:...), если я затем освобожу foo Мне нужно отправить сообщение removeObserver:forKeyPath: в bar в -dealloc?

Ответ 1

Вам нужно использовать -removeObserver:forKeyPath: для удаления наблюдателя до запуска -[NSObject dealloc], так что да, выполнение этого в методе -dealloc вашего класса будет работать.

Лучше, чем это было бы иметь детерминированный момент, когда все, что принадлежит объекту, который выполняет наблюдение, может сказать, что оно сделано, и будет (в конечном счете) освобождено. Таким образом, вы можете прекратить наблюдение сразу же, когда вещь, выполняющая наблюдение, больше не нужна, независимо от того, когда она фактически освобождена.

Это важно иметь в виду, потому что время жизни объектов в Cocoa не так детерминировано, как кажется некоторым людям. Различные каркасы Mac OS X будут отправлять ваши объекты -retain и -autorelease, продлевая срок их службы за пределы того, что вы могли бы подумать, что это будет.

Кроме того, когда вы делаете переход на сборку мусора Objective-C, вы обнаружите, что -finalize будет работать в самые разные моменты времени - и в самых разных контекстах, чем -dealloc. Во-первых, финализация происходит в другом потоке, поэтому вы действительно не можете безопасно отправлять -removeObserver:forKeyPath: другому объекту в методе -finalize.

Придерживайтесь управления памятью (и другого ограниченного ресурса) в -dealloc и -finalize и используйте отдельный метод -invalidate, чтобы владелец сообщил об этом объект, который вы сделали с ним в детерминированной точке; делайте такие вещи, как удаление наблюдений KVO. Цель вашего кода будет более понятной, и у вас будет меньше тонких ошибок, чтобы позаботиться.

Ответ 2

Немного дополнительной информации, которую я получил от мучительного опыта: хотя NSNotificationCenter использует обнуление слабых ссылок при работе под сборкой мусора, KVO этого не делает. Таким образом, вы можете уйти, не удаляя наблюдателя NSNotificationCenter при использовании GC (при использовании сохранения/освобождения вам все равно нужно удалить своего наблюдателя), но вы все равно должны удалить своих наблюдателей KVO, как описывает Крис.

Ответ 3

Определенно согласен с Крисом в управлении "Придерживайтесь памяти (и другого ограниченного ресурса) в -dealloc и -finalize...". Много раз я увижу, что люди пытаются аннулировать объекты NSTimer в своих функциях dealloc. Проблема в том, что NSTimer сохраняет цели. Итак, если целью этого NSTimer является self, dealloc никогда не будет вызван, что приведет к некоторым потенциально неприятным утечкам памяти.

Недействительно в -invalidate и выполните очистку памяти в dealloc и finalize.