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

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

Ответов (3)

Решение

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

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

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

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

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

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

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

Сделайте недействительную -invalidate и прочую очистку памяти в ваших dealloc и finalize.