AVPlayer在Swift 2.2中移除观察者导致崩溃

3

我有一个视频应用程序,几年前我用Swift 1搭建的,现在我一直试图迁移到Swift 2.2。除了与观察器有关的奇怪崩溃之外,所有内容(终于)都正常工作。

func removeObservers()
{
    print("REMOVING OBSERVERS")
    if ( !self.is_image && self.player != nil  ) {
        if (self.player?.observationInfo != nil) {

            self.player?.removeObserver(self, forKeyPath: "currentItem.status")
            self.player?.removeObserver(self, forKeyPath: "readyForDisplay")

        }
    }
    NSNotificationCenter.defaultCenter().removeObserver(self)

}

之前使用SwiftTryCatch时,这段代码可以正常工作,但是现在加上了一些代码后出现了崩溃错误:“'Cannot remove an observer for the key path "readyForDisplay" from because it is not registered as an observer.'”,如果我将这部分代码注释掉,就会出现“已对一个已释放的对象进行观察者注册”的错误。

如果我添加do { } catch {},则会出现“this does not throw”的错误并导致相同的崩溃。请问如何将其放入try-catch格式中?


我曾经遇到过非常类似的问题。你在代码的其他部分中是否删除了那个观察者?最简单的方法可能是统一创建和删除观察者的位置...我在显示后删除了readyForDisplay,但当dealloc出现时无法删除它。 - Putz1103
3个回答

5
在Swift 2中,库对于那些真正意外的错误(会抛出异常)和那些程序员本可以避免的错误(不会抛出异常,但会导致应用崩溃)变得非常严格,这一点有点让人烦恼。(我并不喜欢这种区分,或者至少不喜欢苹果公司在哪些错误属于哪个类别上做出的所有具体决定。在这方面,JSON API 达到了荒谬的地步。但是...我们要使用现有的API。) NSKeyValueObserving文档中说:

如果对象没有被注册为观察者,则调用removeObserver:forKeyPath:是错误的。

“这是一个错误”是苹果公司的代码,表示“您有责任永远不要这样做,如果您这样做,您的应用程序将以无法捕获的方式崩溃。”
在这些情况下,通常有一个API调用可以检查即将执行的操作的有效性。然而,据我所知,没有KVO API调用可以询问“X是否正在观察Z对象的Y键路径”,这意味着您有三个选择:
  • 找出为什么要从未观察的东西中删除观察者,并使用程序自己的内部逻辑来防止这种情况。
  • 保留一个弱实例变量用于“我正在观察的播放器”,并在尝试删除观察者之前检查它是否匹配。
  • 在删除观察者之前将自己添加为观察者。(我相信冗余添加是可以的。)

我尝试添加一个布尔值来表示观察者已经设置,但发现在某些情况下它们被重复删除,所以我修复了它。谢谢。 - Martin

0

statusAVPlayerAVPlayerItem 的属性。

readyForDisplayAVPlayerLayer 的属性。


0

由于您在方法末尾调用了removeObserver(self),为什么不能取消上面的代码注释呢?因为removeObserver(self)会删除所有已注册的观察者。我希望这能解决您的问题。

NSNotificationCenter.defaultCenter().removeObserver(self)

1
KVO通知是否会通过NSNotificationCenter传递?我不确定这是否有效。如果可以的话,了解一下也是好的! - Paul Cantrell

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