KVO и ARC как удалить Observer


87

Как удалить наблюдателя с объекта под ARC ? Мы просто добавляем наблюдателя и забываем об его удалении? Если мы больше не управляем памятью вручную, где мы откажемся от наблюдения?

Например, на контроллере представления:

[self.view addObserver:self
            forKeyPath:@"self.frame"
               options:NSKeyValueObservingOptionNew 
               context:nil];

Раньше я бы вызвал метод removeObserver:контроллера представления dealloc.


4
Обратите внимание, что это очень плохая идея для KVO .frame. Как написано инженерами Apple в StackOverflow, свойство фрейма UIKit не соответствует требованиям KVO. Когда это срабатывает, то только случайно.
steipete

2
Если не ваш будет ключевой путем , @"frame"а не @"self.frame"?
Besi

Ответы:


126

Вы по-прежнему можете реализовать -deallocв ARC, который кажется подходящим местом для удаления наблюдения за ключевыми значениями. Вы просто больше не звоните [super dealloc]из этого метода.

Если -releaseраньше вы преобладали , значит, вы поступали неправильно.


1
Ты уверен насчет этого? Я цитирую clang.llvm.org/docs/… , раздел 7.1.2. dealloc: «Обоснование: даже несмотря на то, что ARC автоматически уничтожает переменные экземпляра, все же есть законные причины для написания метода dealloc, например, для освобождения неиспользуемых ресурсов. Неспособность вызвать [super dealloc] в таком методе почти всегда является ошибкой».
Elise van Looij

@ElisevanLooij Да, это правда. Если вы производите от этого класса, кажется очевидным, что вы должны позвонить [super dealloc]. Кто еще должен сделать это за вас.
Björn Landmesser

@ElisevanLooij Ой, ну, надо было проверять раньше. Не разрешается вызывать [super dealloc]метод dealloc. Не знаю, как это будет работать тогда при создании подкласса упомянутого класса. Возможно, лучше использовать finalizeвместо этого (там, где вы звоните [super finalize])
Бьорн Ландмессер

17
@ElisevanLooij - То, что они пытались сказать, касается случая ручного управления памятью. Поскольку невыполнение вызова [super dealloc]последним в этом методе почти всегда является ошибкой при ручном управлении памятью, компилятор обрабатывает это за вас сейчас, поэтому вы больше не можете вызывать -deallocнапрямую. Единственное, что вы помещаете в -deallocметод в ARC, - это любые не объектные ресурсы, которые вам нужно освободить, или задачи очистки, такие как удаление наблюдателей. Формулировка, которую они используют, немного нечеткая, но они имели в виду именно это.
Брэд Ларсон

7
@ BjörnMilcke - Как я комментирую ответ Элизы, -finalizeиспользуется для этого в сборке мусора, где -deallocникогда не вызывается, но вполне приемлемо разместить этот код в -deallocARC. [super dealloc]вызывается автоматически, поэтому вызывать его в ARC - ошибка.
Брэд Ларсон

1

Я делаю это с помощью этого кода

- (void)dealloc
{
@try{
    [self.uAvatarImage removeObserver:self forKeyPath:@"image" context:nil];
} @catch(id anException) {
    //do nothing, obviously it wasn't attached because an exception was thrown
}
}    

2
В чем смысл обработки исключений dealloc? Слишком поздно что-либо делать.
Abizern

Какой смысл удалять наблюдателей за переменной экземпляра в dealloc? Этот uAvatarImage будет скоро освобожден вместе со всеми наблюдателями, которых он подписал на его ключевые пути.
shoumikhin 07

1
@shoumikhin Я использую ARC, и мне пришлось удалить наблюдателя в методе dealloc. У меня тот же вопрос, что и у вас. Однако, когда я запускал несколько экземпляров класса, в конечном итоге я получил ошибку exc_bad_address. Это разрешило проблему. Кроме того, ответ здесь stackoverflow.com/questions/32490808/… помог мне обнаружить проблему.
mac10688 03

-2

В другом месте, посвященном переполнению стека, Крис Хэнсон советует использовать для этой цели метод finalize и реализовать отдельный метод недействительности, чтобы владельцы могли сообщить объектам, что они выполнены. Раньше я считал, что решения Hanson хорошо продуманы, поэтому я буду придерживаться этого.


13
Обратите внимание, что он имел в виду сборку мусора, а не ARC (его ответ был написан в 2008 году). При сборке мусора -deallocникогда не вызывается. В ARC это так. Совершенно приемлемо удалить наблюдателей KVO, как-dealloc указывает Крис Латтнер (который знает, о чем он говорит) на форумах разработчиков Apple здесь: devforums.apple.com/message/475850
Брэд Ларсон

3
Спасибо, Брэд, за всю эту работу. Нет, чтобы завершить, да, чтобы освободить, но без [super dealloc]. Действительно просто, если вы это знаете. Эй, @drunknbass, прими ответ этого человека!
Elise van Looij
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.