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

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

17.08.2008 21:05:13
3 ОТВЕТА
РЕШЕНИЕ

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

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

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

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

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

38
18.08.2008 00:33:13
Я могу подтвердить из опыта ту боль, которую вы получите в бесконечных авариях, если вы не удалите своих наблюдателей.
Jeff 28.04.2010 23:33:17
Начиная с OS X 10.7 Lion, есть также -removeObserver:forKeyPath:context:, которая позволяет вам передавать в том же контексте, что вы передали -addObserver:forKeyPath:options:context:. Передача уникального контекста гарантирует, что вы не удалите чужое наблюдение, когда удалите свое.
Chris Hanson 1.09.2011 00:33:42
В случае, если это поможет любому, кому я хотел опубликовать это здесь, я регистрировался на уведомление по имени, а затем пытался отменить регистрацию по ключу, что приводило к сбою, заявляющему, что объект не был зарегистрирован для этого уведомления, что меня смущало. Поэтому, если вы регистрируетесь по имени, убедитесь, что вы используете removeObserver:name:object:для отмены регистрации, а не-removeObserver:forKeyPath:context:
Chris Wagner 8.11.2011 01:17:29

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

5
29.08.2008 15:56:34
Это где-то задокументировано?
hpique 6.10.2012 07:48:19

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

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

2
15.09.2008 18:16:34