KVO在尝试使用AV Foundation播放视频时遇到麻烦

时间:2015-10-05 21:31:54

标签: ios swift key-value-observing avplayeritem

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

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

  1. AVPlayerViewController的KVO观察者总是在触发,即使我没有在控制台中注册它(源:请参阅下面的代码列表中的observeForKeyPath()。print(键路径)):
  2.   

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

    1. 我的KVO观察员(“timedMetadata”)未注册。显然:
    2.   

      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
          }
      
         // ...
      
      }
      

      我想要做的就是加载视频网址并播放它。

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

1 个答案:

答案 0 :(得分:0)

运行时错误是因为您将观察结果添加到播放器项目,然后尝试将其从自己移除。

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

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

一般来说,使用KVO进行代码流管理会使您的代码更难以跟踪,调试和维护。最好使用不同的机制并将KVO纯粹保存为变更跟踪和响应。此外,至少保留一个布尔标志,表明您是否正在观察,以便您可以适当地整理。你不能让你的课程被解除分配并留下悬挂的观察。