Подтвердить что ты не робот

Как удалить KVO из слабой собственности?

У меня есть представление (мы будем называть это представление A), которое имеет свойство weak для своего супервизора (вид B). Просмотреть A KVO его супервизор, просмотреть B. С точки зрения Ссылка на вид B является слабым свойством (чтобы предотвратить цикл сохранения), как я могу удалить наблюдателя (наблюдение B)? Просмотр Ссылка на просмотр B получает nil'd, прежде чем у меня есть шанс удалить его.

Выходит B, поскольку контроллер представления имеет сильную ссылку на A. Вот сообщение об утечке журнала:

An instance 0x9ac5200 of class UITableView was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object. Set a breakpoint on NSKVODeallocateBreak to stop here in the debugger. Here the current observation info:
<NSKeyValueObservationInfo 0x8660360> (
<NSKeyValueObservance 0x8660320: Observer: 0x8660020, Key path: contentOffset, Options: <New: YES, Old: NO, Prior: NO> Context: 0x8660020, Property: 0x864ac80>
)

B - это UITableView. Установка точки останова при NSKVODeallocateBreak дает бесполезные результаты.

В A removeFromSuperview я пытаюсь удалить наблюдателя, но ссылка на B уже nil.

Переключение на unsafe_unretained и делать что-то более вручную или вызов [A removeFromSuperview] в контроллере представления dealloc решает проблему. Я хотел бы знать, как решить эту проблему, используя свойство weak.

Здесь соответствующий код: https://gist.github.com/2822776

4b9b3361

Ответ 1

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

С введением ARC Apple должна была обеспечить автоматическое удаление наблюдателей, которые исправили бы подобные случаи, но, к сожалению, этого не произошло. Но я создал свою собственную категорию, которая добавляет эту недостающую функцию: https://github.com/krzysztofzablocki/SFObservers Я объяснил, как это удалось сделать в моем блоге: http://www.merowing.info/2012/03/automatic-removal-of-nsnotificationcenter-or-kvo-observers/

Если вы посмотрите на мое решение, вы заметите, что он гарантирует, что будет вызываться исходный код, даже если один из методов вызывает другие, так что даже если яблоко изменит его внутреннее поведение, категория будет по-прежнему работать нормально:)

Ответ 2

Можно определить явное слабое свойство, ссылающееся на супервизор, а затем наблюдать self с помощью ключевого пути, например @"propertyReferringSuperview.propertyOfSuperview"? Когда вы получаете уведомление KVO, вы проверяете, есть ли self.propertyReferringSuperview == nil и прекратите наблюдение @"propertyReferringSuperview.propertyOfSuperview".

Ответ 3

Вместо добавления слабого свойства вы можете просто использовать свойство superview и реализовать willMoveToSuperview: для добавления/удаления наблюдения KVO.

- (void)willMoveToSuperview:(UIView *)newSuperview {
    [self.superview removeObserver:self forKeyPath:@"contentOffset" context:context];
    [newSuperview addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:context];
    [super willMoveToSuperview:newSuperview]; // optional as default implementation does nothing
}