我一直在尝试使用我放入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)")
}
解决此问题的最佳方法是什么?
答案 0 :(得分:0)
注意:解决此问题需要将任务卸载到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对于这种特定情况可能更好,因为视频是由用户启动的操作加载的。
关于视频的实际缓存。我不是太熟悉AVPlayer
或AVPlayerItem
,但根据我的理解,您可以提供给AVPlayer
的更多元数据(即持续时间,曲目等)在尝试在图层中渲染视频之前,它的速度越快(请参阅此相关StackOverflow Question)。
此外,您可能希望查看iOS 10中新引入的API,以便您在表格视图中预取单元格。如果您利用预取优化,您可能会在AVPlayer
中请求单元格显示cellForRowAtIndexPath:
之前加载AVKit
所需的所有内容。
无论如何,希望你能从那里开始并解决问题。绝对花点时间阅读GCD
,UITableView
和let 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)。