0

目标:
我最终试图读取外部视频文件(.mp4、.mpg ...);在 AVPlayerViewController 的一个实例中。

但是我遇到了各种各样的 KVO 问题。

  1. AVPlayerViewController 的 KVO 观察者总是在触发,即使我没有像这里的控制台中显示的那样注册它(来源:参见下面代码列表中的 observeForKeyPath().print(key path)):

playerController.status playerController.contentDimensions playerController.playingOnExternalScreen playerController.externalPlaybackType playerController.allowsExternalPlayback playerController.hasEnabledVideo playerController.hasEnabledAudio bounds videoScaled playerController.playingOnExternalScreen view.viewWindowState bounds playerController.playing

  1. 我的 KVO 观察者(“timedMetadata”)没有注册。显然:

self.playerItem!.addObserver(self, forKeyPath: "timedMetadata", options: NSKeyValueObservingOptions.New, context: nil)

不工作:
a) 'observeValueForKeyPath()' 没有为这个观察者触发;b)我收到以下运行时
错误(在立即删除观察者作为测试之后):

...原因:'无法删除观察者...对于关键路径“timedMetadata”来自...,因为它没有注册为观察者。'

    class EditShowVideoViewController:AVPlayerViewController {

    var playerItem:AVPlayerItem?

    override func viewDidLoad() {

        self.view.hidden = true

        if let url = NSURL(string: gEditMediumTuple!.medium as! String) {
            let asset = AVURLAsset(URL: url)
            let requestedKeys = Array(arrayLiteral: "tracks", "playable")
            asset.loadValuesAsynchronouslyForKeys(requestedKeys, completionHandler: { ()  in
                // do something
                dispatch_async(dispatch_get_main_queue(), {
                    self.playerItem = AVPlayerItem(asset: asset)
                    self.playerItem!.addObserver(self, forKeyPath: "timedMetadata", options: NSKeyValueObservingOptions.New, context: nil)
                    self.removeObserver(self, forKeyPath:"timedMetadata") //...still runtime error.
                })
            })

        } else {
            showAlert(sender: self.parentViewController!, withTitle: "No Video", withMessage: "No video is found.", alertPurpose: .noVideo)
        }
    }

    override func observeValueForKeyPath(keyPath: String?,
        ofObject object: AnyObject?, change: [String : AnyObject]?,
        context: UnsafeMutablePointer<()>) {
            print(keyPath!)
            guard keyPath == "readyForDisplay" else {return}
            guard let obj = object as? AVPlayerViewController else {return}
            guard let ok = change?[NSKeyValueChangeNewKey] as? Bool else {return}
            guard ok else {return}
            dispatch_async(dispatch_get_main_queue(), {
                self.finishConstructingInterface(obj)
            })

            self.removeObserver(self, forKeyPath:"timedMetadata")
    }

    func finishConstructingInterface (vc:AVPlayerViewController) {
        self.removeObserver(self, forKeyPath:"readyForDisplay")
        self.view.hidden = false
    }

   // ...

}

我想要做的就是加载一个视频 URL 并播放它。

如果缺乏补救措施,欢迎提出任何建议。

4

1 回答 1

0

运行时错误是因为您将观察添加到播放器项目,但随后尝试将其从 self.

在观察者回调中,如果键不属于您的观察,那么您应该调用 super。你不知道你不这样做会破坏什么。

考虑将视频 VC 添加为子类,而不是将您的类添加为子类。这将使其在逻辑上保持独立并防止 KVO 回调的混淆。

一般来说,使用 KVO 进行代码流管理会使您的代码更难于遵循、调试和维护。最好使用不同的机制并保存 KVO 纯粹用于更改跟踪和响应。此外,至少保留一个布尔标志,表明您是否正在观察,以便您可以适当地进行整理。你不能让你的班级被释放并留下一个悬而未决的观察。

于 2015-10-06T06:51:10.130 回答