繁体   English   中英

NSKeyValueObservation:无法从对象中删除关键路径的观察者,因为它未注册为观察者

[英]NSKeyValueObservation: Cannot remove an observer for the key path from object because it is not registered as an observer

我在我的应用程序中遇到随机崩溃(我无法在我拥有的设备上重现),例外情况:

无法从AVPlayerLayer 0xaddress中删除关键路径“readyForDisplay”的观察者Foundation.NSKeyValueObservation 0xaddress,因为它未注册为观察者。

当我释放包含AVPlayerLayer的UIView时会发生这种情况。

我的初学者:

private var playerLayer : AVPlayerLayer { return self.layer as! AVPlayerLayer }

init(withURL url : URL) {
    ...
    self.asset = AVURLAsset(url: url)
    self.playerItem = AVPlayerItem(asset: self.asset)
    self.avPlayer = AVPlayer(playerItem: self.playerItem)
    super.init(frame: .zero)
    ...
    let avPlayerLayerIsReadyForDisplayObs = self.playerLayer.observe(\AVPlayerLayer.isReadyForDisplay, options: [.new]) { [weak self] (plLayer, change) in ... }
    self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]
    ...
    }

我的deinit抛出异常:

deinit {
    self.kvoPlayerObservers.forEach { $0.invalidate() }
    ...
    NotificationCenter.default.removeObserver(self)
}

根据Crashlytics的说法,它发生在不同iPhone上的iOS 11.4.1上。

导致deinit的代码非常简单:

// Some UIViewController context.
self.viewWithAVLayer?.removeFromSuperview()
self.viewWithAVLayer = nil

我会很感激为什么会这样。

我已经看到了这个错误,但它似乎不是我的原因。

编辑1:

后人的其他信息。 在iOS 10上,如果我没有失效,我会在deinit上获得可重现的崩溃。 在iOS 11上,它可以无失效地工作(如果我没有失效并且让观察者被我的类deinit ,则崩溃消失时尚未检查)。

编辑2:

后代的其他信息:我也发现了这个可能与之相关的Swift bug - SR-6795

self.kvoPlayerObservers.forEach { $0.invalidate() }

self.kvoPlayerObservers.removeAll()

我也不喜欢这一行:

self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]

kvoPlayerObservers应该是一个Set,你应该在收到它们时逐个插入观察者。

我接受了亚特的答案,但我想提供更多关于我如何解决问题的信息。

我的deinit没有崩溃看起来像这样:

if let exception = tryBlock({ // tryBlock is Obj-C exception catcher.
        self.kvoPlayerObservers.forEach { $0.invalidate() };
        self.kvoPlayerObservers.removeAll()
}) {
    remoteLoggingSolution.write(exception.description)
}
... // do other unrelated stuff

基本上我尝试捕获Obj-C异常,如果它发生并尝试远程记录它。

我有这个代码在生产过去2周,从那时起我既没有收到崩溃也没有收到异常日志,所以我假设matt的建议添加kvoPlayerObservers.removeAll()是正确的(至少对于我的特殊情况)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM