Лучшая практика удаления объекта в качестве наблюдателя для некоторого свойства KVO

Я хотел знать, какие лучшие практики для добавления и удаления себя как наблюдателя для некоторого свойства KVO. Я добавил объект контроллера в качестве наблюдателя для "скрытого" свойства UIView. Я добавил наблюдателя в loadView моего контроллера. Теперь, что является лучшим местом для регистрации DE в качестве наблюдателя для этого свойства. Я хочу прекратить наблюдать, как только вид диспетчера представлений отклоняется. Время от времени я вижу ниже предупреждения консоли и время от времени я рушился из-за удаления в качестве наблюдателя.

Любые предложения?

An instance 0x190659e0 of class UIView 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:

Ответ 1

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

В практическом плане это означает, что вы действительно не должны что-то наблюдать, если у вас нет никакого контроля над его жизненным циклом, т.е. у вас нет сильной ссылки на него. Если у вас есть сильная ссылка на него, вам нужно отменить регистрацию до того, как ваша сильная ссылка исчезнет. Как правило, я обрабатываю это, чтобы обрабатывать незарегистрированность по старому значению и регистрации нового значения в настраиваемом сетевом элементе для свойства (сильного), относящегося к объекту, который должен наблюдаться. Затем, в dealloc, я также отменил регистрацию моего соблюдения. Что-то вроде этого:

- (void)setSomeView:(NSView *)someView
{
    if (someView != _someView) {
        [_someView removeObserver:self forKeyPath:@"someKey"];
        _someView = someView;
        [_someView addObserver:self forKeyPath:@"someKey" options:0 context:NULL];
    }
}

- (void)dealloc
{
    [_someView removeObserver:self forKeyPath:@"someKey"];
}

Таким образом, я наблюдаю только объекты, у которых есть сильная (владеющая) ссылка, поэтому они не могут быть освобождены из-под меня. И, когда я освободился, я также отменил регистрацию для наблюдения.

Ответ 2

зависит от того, когда вы зарегистрируетесь для него:

  • если вы зарегистрируетесь в viewWilllAppear - отмените регистрацию в viewWillDisappear
  • если вы зарегистрируетесь в viewDidLoad/loadView - отмените регистрацию в dealloc

конечно, есть еще несколько вариантов. Идея состоит в том, чтобы найти "метод-контрагент", чтобы вы регистрировались и разделители были сбалансированы.

Ответ 3

Для тех, кто спрашивает об этом с помощью Swift 3.0, см. приведенный ниже код, который только что мне помог:

override function viewDidLoad() {
super.viewDidLoad()

// some code

 webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: .new, context: nil)

    }

deinit {
        webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
    }

Deinit удаляет наблюдателя перед тем, как освободить набор WKWebview и изменить navigationController.

Надеюсь, что это поможет