【问题标题】:AVPlayer.play() in UITableViewCell briefly blocks UIUITableViewCell 中的 AVPlayer.play() 会短暂阻塞 UI
【发布时间】:2016-05-31 12:31:54
【问题描述】:

我正在尝试将内联视频添加到我的 UITableViewCells 中,例如 Instagram、Twitter、Vine 等。我正在使用 AVPlayerController 和自定义单元格测试带有本地视频文件的 UI(请参阅下面的示例代码)。我等待 AVPlayer 的状态为 ReadyToPlay,然后播放视频。

问题在于,当在 tableView 上滚动时,每当加载视频单元格时,UI 会冻结一小部分,这使得应用程序看起来很笨重。当一行中有多个视频单元时,这种效果会变得更糟。任何想法和帮助将不胜感激

表格视图代码:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

     let cell = tableView.dequeueReusableCellWithIdentifier("videoCell", forIndexPath: indexPath) as! CustomCell

     //Set up video player if cell doesn't already have one
     if(cell.videoPlayerController == nil){
         cell.videoPlayerController = AVPlayerViewController()
         cell.videoPlayerController.view.frame.size.width = cell.mediaView.frame.width
         cell.videoPlayerController.view.frame.size.height = cell.mediaView.frame.height 
         cell.videoPlayerController.view.center = cell.mediaView.center
         cell.mediaView.addSubview(cell.videoPlayerController.view) 
     }

     //Remove old observers on cell.videoPlayer if they exist
     if(cell.videoObserverSet){
         cell.videoPlayer.removeObserver(cell, forKeyPath: "status")
     }


     let localVideoUrl: NSURL = NSBundle.mainBundle().URLForResource("videoTest", withExtension: "m4v")!
     cell.videoPlayer = AVPlayer(URL:localVideoUrl)
     cell.videoPlayer.addObserver(cell, forKeyPath:"status", options:NSKeyValueObservingOptions.New, context = nil)
     cell.videoObserverSet = true         

     cell.videoPlayerController.player = cell.videoPlayer


     return cell
}

自定义细胞观察者代码

override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {

    if(keyPath=="status"){
        print("status changed on cell video!");

        if(self.videoPlayer.status == AVPlayerStatus.ReadyToPlay){

            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.videoPlayer.play()
            })
        }
    }
}

我还尝试使用 loadValuesAsynchronouslyForKeys(["playable"]) 加载视频的 AVAsset 版本,但这对 UI 块也没有帮助。

如何才能获得如丝般流畅的 Instagram 视频播放和滚动功能?

【问题讨论】:

  • 在 Instruments 的 Time Profiler 下运行它。将采样间隔设置为 40 µs(这似乎是最小值),看看您是否可以了解故障期间它在做什么。然后,您可以尝试将主线程中的所有内容移出。
  • 谢谢,我一定会调查的

标签: objective-c swift uitableview avplayer avplayerviewcontroller


【解决方案1】:

另一个更新 强烈推荐使用 Facebook 的 Async Display Kit ASVideoNode 作为 AVPlayer 的替代品。在加载和播放视频时,您将获得如丝般流畅的 Instagram 桌面视图性能。我认为 AVPlayer 在主线程上运行了一些进程,并且无法绕过它们,因为它发生在相对较低的级别。

更新:已解决

我无法直接解决这个问题,但我习惯了一些技巧和假设,并获得了我想要的性能。

假设是没有办法避免视频在主线程上加载一定的时间(除非你是 instagram 并且你拥有一些 AsyncDisplayKit 魔法,但我不想这样做) ,所以不要尝试删除 UI 块,而是尝试隐藏它。

我通过在我的 tableView 上实现一个简单的 isScrolling 检查来隐藏 UIBlock

func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) {

    if(self.isScrolling){
        if(!decelerate){
            self.isScrolling = false
            self.tableView.reloadData()
        }
    }
}

func scrollViewDidEndDecelerating(scrollView: UIScrollView) {

    if(self.isScrolling){
        self.isScrolling = false
        self.tableView.reloadData()
    }
}

func scrollViewWillBeginDragging(scrollView: UIScrollView) {
    self.isScrolling = true
}

然后确保在 tableView 滚动或视频已经播放时不要加载视频单元格,并在滚动停止时重新加载 tableView。

if(!isScrolling && cell.videoPlayer == nil){

    //Load video cell here
}

但请确保移除 videoPlayer,并在 videoCell 不再出现在屏幕上时停止收听重播通知。

func tableView(tableView: UITableView, didEndDisplayingCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {

    if(tableView.indexPathsForVisibleRows?.indexOf(indexPath) == nil){

        if (cell.videoPlayer != nil && murmur.video_url != nil){

            if(cell.videoPlayer.rate != 0){

                cell.videoPlayer.removeObserver(cell, forKeyPath: "status")
                cell.videoPlayer = nil;
                cell.videoPlayerController.view.alpha = 0;
            }
        }
    }
}

通过这些更改,我能够一次在屏幕上实现具有多个 (2) 视频单元的流畅 UI。希望这会有所帮助,如果您有任何具体问题或我所描述的内容不清楚,请告诉我。

【讨论】:

  • 所以您实际上并没有解决这个问题,而是仅在滚动停止时才显示视频播放器,这基本上仍然会阻塞 UI (?)
  • 是的,这是一个 hack,我们只在滚动停止时播放视频。一旦视频已经在播放,您就可以继续滚动没有问题,但我们只会在视频出现在屏幕上并且滚动停止时才开始播放。上次我检查时,我相信 Twitter 在他们的 iOS 应用程序中实施了类似的策略。这是使用 AVPlayer 的缺点之一。但我强烈推荐 Facebook 的 AsyncDisplayKit,它有一个 ASVideoNode 对象,它可以替代 AVPlayer,而且它是从头开始构建的,不会阻塞主线程。出色的表现。
  • 感谢您的回答。但是我尝试了 AsyncDisplayKit,但它完全失败了。它只是 AVPlayer 的一个包装器,没有什么新东西,而且非常有限。我认为解决这个问题的唯一方法是实现一个完全自己的播放器,但不幸的是,这需要很长时间才能完成..
猜你喜欢
  • 2019-04-02
  • 1970-01-01
  • 2012-01-30
  • 2021-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-29
相关资源
最近更新 更多