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
Чи не повинен бути ваш keyPath @"frame"швидше ніж @"self.frame"?
Бесі

Відповіді:


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])
Björn Landmesser

17
@ElisevanLooij - Сенс, який вони намагалися зробити там, стосується справи про ручне керування пам'яттю. Оскільки не виклик [super dealloc]останнього в цьому методі - це майже завжди помилка при ручному керуванні пам’яттю, компілятор обробляє це за вас зараз, саме тому ви більше не можете дзвонити -deallocбезпосередньо. Єдине, що ви вкладаєте в -deallocметод під ARC, - це будь-які не об’єктні ресурси, які вам потрібно звільнити, або завдання очищення, такі як видалення спостерігачів. Формулювання, яке вони використовують, трохи мутне, але саме це вони мали на увазі.
Бред Ларсон

7
@ BjörnMilcke - Коли я коментую відповідь Елізи, -finalizeвикористовується для цього під збір сміття, де -deallocніколи не викликається, але цілком прийнятно розміщувати цей код -deallocпід ARC. [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

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

-2

В іншому місці при переповненні стека Кріс Хенсон радить використовувати для цього метод finalize та застосувати окремий метод недійсності, щоб власники могли повідомляти об’єктам, що вони виконані. У минулому я вважав, що рішення Гансона є продуманими, тому я піду з цим.


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

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