在tableview中平滑加载视频

时间:2017-03-30 12:55:20

标签: ios swift uitableview

我一直在尝试使用我放入TableView Cell的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)")
    }

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

1 个答案:

答案 0 :(得分:0)

谢天谢地,你好运。 iOS针对这些类型的问题进行了优化。 Apple工程师不遗余力地提供API来帮助您实现黄油平滑滚动同时加载您的内容。

  

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

首先,要知道cellForRowAtIndexPath:方法应该通常在主线程上调用您的数据源。这意味着在此方案中未正确使用您DispatchQueue.main.async的呼叫。

相反,您需要做的是将AVPlayer缓存卸载到单独的后台线程,然后返回主线程更新单元格&#39 ; s层内容。另外,你不应该在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:之前加载AVKit所需的所有内容。

无论如何,希望你能从那里开始并解决问题。绝对花点时间阅读GCDUITableViewlet rangeValueElement = document.querySelector('#range'); let shippingValueElement = document.querySelector('#shipping'); function calculateShipping(price) { const priceShippingRelation = { 1: 43.51, 2: 47.05, 3: 50.61, 4: 54.15, 5: 57.71, 6: 61.25, 7: 64.81, 8: 68.35, 9: 71.91, 10: 75.45, 11: 79.31, 12: 83.15, 13: 87.01, 14: 90.85, 15: 94.71, 16: 98.55, 17: 102.41, 18: 106.25, 19: 110.11, 20: 113.95, 21: 117.81, 22: 121.65, 23: 125.51, 24: 129.35, 25: 133.21, 26: 137.05, 27: 140.91, 28: 144.75, 29: 148.61, 30: 152.45, 31: 158.31, 32: 160.15, 33: 164.01, 34: 167.85, 35: 171.71, 36: 175.55, 37: 179.41, 38: 183.25, 39: 187.11, 40: 190.95, /* ... */ 42: 136, /* ... */ 65: 220 }; return priceShippingRelation[price]; } document.querySelector('input#valR').addEventListener('change', showVal); function showVal() { rangeValueElement.innerText = this.value; shippingValueElement.innerText = 'Priority Mail (frete): $ ' + calculateShipping(this.value); } console.log(calculateShipping(3));上的文档(特别是新的预取API)。