КВО очистки отдельных наблюдаемых ключей - PullRequest
1 голос
/ 20 января 2012

Скажем, у меня есть список объектов модели и объекта контроллера, который заинтересован в изменениях свойств отдельного объекта модели. Когда я добавляю объект, я использую addObserver для каждого ключа, который заинтересован в использовании KVO между контроллером и объектом модели. Теперь, когда один из наблюдаемых объектов исчезает, мне нужно сказать контроллеру вида прекратить наблюдать изменения этого отдельного объекта для конкретного ключа.

Что такое элегантный способ сделать это? Лучший способ, о котором я могу подумать, это добавить новый ключ kRemoveObject, который я вызываю addObserver, в моем контроллере, который запускается непосредственно перед удалением объекта. Затем я удаляю все наблюдаемые ключи, включая kRemoveObject для конкретного экземпляра. Кто-нибудь знает более чистый путь? Это кажется немного громоздким.

Ответы [ 3 ]

0 голосов
/ 21 января 2012

При использовании КВО наблюдатель должен хранить ссылку на то, что он наблюдает. Если он делает это, то объект никогда не может «уйти» (если вы имеете в виду быть освобожденным), потому что у наблюдателя тоже есть ссылка.

Если вы хотите прекратить наблюдать это, сделайте это от наблюдателя.

Если вы просто ждете изменения одного значения, то при получении уведомления - удалите наблюдателя. (Примите меры предосторожности, чтобы не удалить наблюдателя, если он уже удален).

В деллоке вашего наблюдателя вы очистите - удалив все оставшиеся наблюдения на объектах.

Это может быть случай сохранения массива наблюдаемых объектов в наблюдателе, чтобы отслеживать их - я видел, что это использовалось, но мне это не нравится, и оно не очень гибкое.

Что мне нравится, так это класс, который я назвал KVOHelper. Вы создаете это в классе наблюдения и передаете объект, который вы наблюдаете, наблюдатель и ключевой путь. Это обертка вокруг КВО. Вы можете удалить наблюдателя, если хотите - или просто отпустить KVOHelper, и в своей процедуре Deloc это удалит наблюдателя перед тем, как выпустить все. Это гарантирует, что вы не можете удалить одного и того же наблюдателя более одного раза (что вызовет исключение). Он также поставляется в комплекте с KVOHelperSet для управления несколькими KVOHelper. Я не могу взять кредит на написание этого класса - я получил это от парня, с которым я работал над проектом. Но я использую это все время сейчас - и это работает хорошо. Принцип прост, и вы должны быть в состоянии создать свой собственный.

0 голосов
/ 21 января 2012

Я нашел этот очень элегантный способ сделать это, и он решает одну из вещей, которая всегда беспокоила меня в KVO, - это большой «оператор switch», который KVO добавляет с наблюдаемым значениемValueForKeyPath.KVO + Blocks - это очень круто, он исключает этот «оператор switch» и автоматически обрабатывает удаление наблюдателя, поэтому нет необходимости вызывать removeObserver при использовании ARC (если вы делаете свое собственное управление памятью, тогда я думаю, что вам нужно вызвать removeObserverWithBlockToken, хотяЯ не пробовал это).

http://blog.andymatuschak.org/post/156229939/kvo-blocks-block-callbacks-for-cocoa-observers

Код здесь: https://gist.github.com/153676

Одна вещь, о которой следует помнить, но в целом относится к блокам, это если вы ссылаетесь на себя в своем блоке,Вам нужно сделать это:

__block blockSelf = self; 

, если вы этого не сделаете, у вас будет цикл сохранения.(подробнее см. Сохранение цикла для `self` с блоками ).

Еще одна вещь, она работает с ARC, если вы положили -fno-objc-arc на файл.(Подробности см. В этом разделе Как отключить ARC для одного файла в проекте? )

Я надеюсь, что Apple добавит что-то подобное в SDK.

0 голосов
/ 20 января 2012

с макушки головы:

Включить наблюдаемый объект для получения ссылки на контроллер. Пусть наблюдаемый объект вызывает функцию removeObserver: forKeyPath:. Контроллер должен будет предоставить список keyPaths.

(РЕДАКТИРОВАТЬ: супер чистый способ сделать это было бы определение протокола делегата (с помощью метода "imDying") для вашего наблюдаемого объекта, добавить свойство делегата к наблюдаемому объекту, установив контроллер в качестве делегата, и если наблюдаемый объект вызывает делегатский метод «imDying» в dealloc. Замените «imDying» на лучшее имя, хе.)

Или:

Пусть контроллер управляет сроком службы наблюдаемого объекта, позволяя вам удалить себя до освобождения наблюдаемого объекта.

...