删除KVO属性的观察者对象的最佳实践

5
我想知道添加和删除KVO属性的最佳做法。我将我的控制器对象作为UIView的“hidden”属性的观察者添加了进去。我在我的视图控制器的loadView中添加了观察者。现在,最好的取消此属性观察者的地方是哪里?当视图控制器的视图被关闭时,我想尽快停止观察。有时我会看到下面的控制台警告消息,有时由于过度删除观察者而崩溃。

有什么建议吗?

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's the current observation info:
4个回答

15

大致上来说,当您不再需要KVO观察时,需要取消注册。为了防止您看到的错误,您需要确保在被观察对象被释放之前注销。

从实际角度来看,这意味着如果您无法控制对象的生命周期,即没有强引用它,那么您真的不应该观察它。如果您有一个 strong 引用它,那么您需要在该 strong 引用消失之前注销。通常我处理这个问题的方法是,在自定义属性的 setter 方法中处理旧值的注销和新值的注册(引用要观察的对象的 strong 属性)。然后在 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"];
}

这样,我只观察那些我有强(拥有)引用的对象,因此它们不会在我下面被解除分配。当我被解除分配时,我也取消注册观察。


4

取决于您注册时间的不同:

  • 如果您在viewWillAppear中注册 - 在viewWillDisappear中注销
  • 如果您在viewDidLoad / loadView中注册 - 在dealloc中注销

当然还有更多选项.. 关键是找到“对应方法”,使您的注册和注销保持平衡。


1
在iOS5以下,你必须了解 viewDidUnload。 - Daij-Djan

0

Swift 4

var observer: NSKeyValueObservation?

self.observer = myPlayer.observe(\.rate, options:  [.new, .old], changeHandler: { (player, change) in
     if player.rate == 1  {
          print("Playing")
      }else{
           print("Stop")
      }
 })

 // Later You Can Remove Observer      
 self.observer?.invalidate()

0

对于任何使用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))
    }

在释放 WKWebview kit 和更改 navigationController 之前,deinit 会移除观察者。

希望这可以帮到你。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接