KVO 在尝试使用 AV Foundation 流式播放视频时遇到麻烦
Posted
技术标签:
【中文标题】KVO 在尝试使用 AV Foundation 流式播放视频时遇到麻烦【英文标题】:KVO hassles whilst trying to stream-play a video using AV Foundation 【发布时间】:2015-10-05 21:31:53 【问题描述】:目标: 我最终试图读取外部视频文件(.mp4、.mpg ...);在 AVPlayerViewController 的一个实例中。
但是我遇到了各种各样的 KVO 问题。
-
AVPlayerViewController 的 KVO 观察器总是在触发,即使我没有按照此处的控制台所示注册它(来源:请参阅下面代码列表中的 observeForKeyPath().print(key path)):
playerController.status playerController.contentDimensions playerController.playingOnExternalScreen playerController.externalPlaybackType playerController.allowsExternalPlayback playerController.hasEnabled视频 playerController.hasEnabledAudio bounds videoScaled playerController.playingOnExternalScreen view.viewWindowState 边界 playerController.playing
-
我的 KVO 观察者(“timedMetadata”)没有注册。显然:
self.playerItem!.addObserver(self, forKeyPath: "timedMetadata", 选项:NSKeyValueObservingOptions.New,上下文:无)
不工作: 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 并播放它。
如果缺乏补救措施,欢迎提出任何建议。
【问题讨论】:
【参考方案1】:运行时错误是因为您将观察添加到播放器项目,但随后尝试将其从自身中删除。
在观察者回调中,如果键不属于您的观察,那么您应该调用 super.你不知道你不这样做会破坏什么。
考虑将视频 VC 添加为子类,而不是将您的类添加为子类。这将使其在逻辑上保持独立并防止 KVO 回调混淆。
一般来说,使用 KVO 进行代码流管理会使您的代码更难遵循、调试和维护。最好使用不同的机制并保存 KVO 纯粹用于更改跟踪和响应。此外,至少保留一个布尔标志,表明您是否正在观察,以便您可以适当地进行整理。你不能让你的班级被释放并留下一个悬而未决的观察。
【讨论】:
我特意在声明后立即添加了“删除”以查看它是否起作用;这是我担心的问题之一 - 说观察员没有注册。我添加了 super.callback。如果可以的话,我想避免使用 KVO,我会用什么来指示视频已准备好显示?有没有可以处理这个的 NSNotification 对象? 但删除是在不同的对象上以上是关于KVO 在尝试使用 AV Foundation 流式播放视频时遇到麻烦的主要内容,如果未能解决你的问题,请参考以下文章