【问题标题】:Smooth loading of videos in tableview在 tableview 中平滑加载视频
【发布时间】:2017-03-30 12:55:20
【问题描述】:

我一直在尝试使用放置在 TableView 单元中的 AVPlayer 将一些视频添加到我的 tableView 中。

但在加载视频时 UI 会冻结。

这是我在 indexpath 中的 cellforRow。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCel {


    var tableCell : UITableViewCell? = nil

    if (tableCell == nil){

        tableCell = tableView.dequeueReusableCell(withIdentifier: "cell")
    }

    let view = tableCell?.viewWithTag(9999)
    tableCell?.tag = indexPath.row


    DispatchQueue.main.async {
         if (tableCell?.tag == indexPath.row){
                let player = self.cache.object(forKey: indexPath.row as AnyObject) as! AVPlayer
                let playerLayer = AVPlayerLayer(player: player)
                playerLayer.frame = (view?.bounds)!
                view?.layer.addSublayer(playerLayer)
                player.play()

            }

//            tableView.reloadData()
    }

 return tableCell!
}

这就是我将视频添加到缓存的方式。

    for i in 0...10{

        var videoURL : URL? = nil

        if (i%2 == 0){

            videoURL = URL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
        }else{

            videoURL = URL(string: "http://techslides.com/demos/sample-videos/small.mp4")

        }
        let player = AVPlayer(url: videoURL!)

        arr?.append(player)

        self.cache.setObject(player, forKey: i as AnyObject)
        print("count = \(arr?.count)")
    }

解决此问题的最佳方法是什么?

【问题讨论】:

  • 你是怎么解决的?
  • @FaridAlHaddad 我进行了设计更改,这部分被取消了。在新设计中,我必须导航到新页面,然后从那里显示视频。
  • 哦好的..谢谢!

标签: ios swift uitableview


【解决方案1】:

谢天谢地,你很幸运。 iOS 仅针对这些类型的问题进行了优化。 Apple 工程师竭尽全力提供 API 来帮助您实现流畅的滚动同时加载您的内容。

注意:解决此问题需要将任务卸载到 CPU 上的不同线程。它可能会变得复杂,并且有很多东西需要学习。我强烈建议您阅读 Apple 的文档。

首先,要知道cellForRowAtIndexPath: 方法应该通常在主线程上调用您的数据源。这意味着您必须拨打DispatchQueue.main.async 在这种情况下不合适。

相反,您需要将 AVPlayer 缓存卸载到单独的后台线程,然后返回主线程以更新单元格的图层内容。此外,您不应该在cellForRowAtIndexPath: 中这样做。您可能需要继承 UITableViewCell 并在其中编写自己的加载序列 - 这样,您可以快速 init 您的自定义单元格,将其交还给 cellForRowAtIndexPath: (然后可以愉快地继续),并且继续从单元子类中加载和更新。

要在后台线程中设置您的 AVPlayer,请执行以下操作:

DispatchQueue.global(qos: .background).async {
    // Background thread
    // Do your AVPlayer work here

    // When you need to update the UI, switch back out to the main thread
    DispatchQueue.main.async {
        // Main thread
        // Do your UI updates here
    }
}

您可能希望查看在创建后台线程时传入的服务质量值。对于这种特定情况,userInitiated QOS 可能会更好,因为加载视频是用户启动操作的结果。

至于视频的实际缓存。我对AVPlayerAVPlayerItem 不太熟悉,但据我了解,您可以在尝试渲染视频之前将更多元数据(即持续时间、曲目等)提供给AVPlayer在一个层中,它运行得越快(参见这个相关的StackOverflow Question)。

此外,您可能还想查看 iOS 10 中新引入的 API,您可以在表格视图中预取单元格。如果您利用预取优化,您可能会在后台加载 AVPlayer 所需的所有内容,并且远远早于请求在 cellForRowAtIndexPath: 中显示单元格之前。

无论如何,希望您可以从那里开始并解决问题。一定要花时间阅读有关 AVKitGCDUITableView 的文档(特别是新的预取 API)。

【讨论】:

  • 谢谢 Samuel,我可以看到 tableCell 滚动有巨大的性能提升。我相信我可能还需要在缓存部分做一些修改。
  • 在快速滚动的情况下,TableView 单元格可能会离开用户的视图,而后台线程可能仍在执行。如果我在UITableViewCell 子类中执行DispatchQueue.global,我应该如何知道单元何时出队以取消异步进程?任何的想法?否则可能会成为内存泄漏的情况......
猜你喜欢
  • 1970-01-01
  • 2018-08-02
  • 2019-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多