2012-01-19 2 views
1

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

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

ответ

0

Я нашел этот очень элегантный способ сделать это, и он решает одну из вещей, которая всегда беспокоила меня о KVO, которая является большой «операцией switch», которую добавляет KVO с помощью функции registerValueForKeyPath.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; 

Если вы этого не сделаете, вы закончите цикл сохранения. (см. Retain cycle on `self` with blocks).

Другое дело, оно работает с ARC, если вы поместите в файл -fno-objc-arc. (См. Это подробности How can I disable ARC for a single file in a project?)

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

+0

__block не прерывает цикл сохранения. Вы должны использовать __weak – user1687195

+0

KVO не заставляет вас использовать большой оператор switch. Если вы делаете это так, вы можете пересмотреть свою реализацию. – quellish

0

С верхней части моей головы:

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

(EDIT: Супер чистый способ сделать это будет определять протокол делегата (с методом «imDying») для вашего наблюдаемого объекта, добавить свойство делегата к вашему наблюдаемому объекту, установив контроллер в качестве делегата , и с наблюдаемым-объект называют «imDying» метод делегата в dealloc Заменить «imDying» с лучшим именем, хех)

Или:..

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

+0

Благодарим за предложения. Моя проблема с подходом делегата заключается в том, что он использует другой механизм, чем KVO, и каждый объект, который хотел бы его соблюдать, должен был принять этот протокол. Для второго предложения задача модели состоит в том, чтобы управлять продолжительностью жизни объектов. Только модель действительно знает, когда что-то уходит, и контроллер должен быть отключен от изменений в модели. – possen

+0

- Удалено мое упоминание о NSNotificationCenter, поскольку это не используется KVO. – MechEthan

+0

Угадайте, что я получаю, похоже, что должен быть способ сделать это с помощью методов KVO. Поэтому, возможно, решение, которое я изложил, - единственный способ сделать это. – possen

0

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

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

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

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

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

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

Смежные вопросы