我有一个UITableView
,其中包含许多在滚动时播放的视频。由于tableView中的单元格正在重复使用,因此我只为每一行实例化一个AVPlayer
。当一个单元被重用时,我只需通过调用PlayerItem
来更改该单元播放器的[self.player replaceCurrentItemWithPlayerItem:newItem];
。目前,这是在tableView:cellForRowAtIndexPath
内部间接调用的。向下滚动时,重新使用时会有明显的滞后。通过消除过程,我得出结论,延迟是由replaceCurrentItemWithPlayerItem
引起的,甚至还没有开始播放。删除单行代码(防止播放器获得新视频)时,滞后现象消失了。
我已尝试解决的问题:
我有一个自定义的UITableViewCell
来播放这些视频,并且在其中创建了一个方法,以使用来自对象的新信息进行初始化。即,在cellForRowAtIndexPath:
中,我调用[cell initializeNewObject:newObject];
来执行以下方法:
//In CustomCell.m
-(void)initializeNewObject:(CustomObject*)newObject
{ /*...*/
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
AVPlayerItem *xPlayerItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:newObject.url]];
AVPlayer *dummy = self.player;
[dummy replaceCurrentItemWithPlayerItem:xPlayerItem];
dispatch_async(dispatch_get_main_queue(), ^{
self.player = dummy;
playerItem = xPlayerItem;
}
}/*...*/
}
运行此命令时,得到的结果与完全删除更换项的调用相同。显然,该函数无法进行线程化。
我不太确定我对此有什么期望。我以为我需要干净的
copy
的AVPlayer
才能起作用,但是经过一番搜索,我发现了几条评论,指出replaceCurrentItemWithPlayerItem:
可以在单独的线程中调用而不是,这对我来说没有意义。我知道,UI元素绝不应在除主线程/ UI线程之外的其他线程中处理,但我永远也无法想象replaceCurrentItemWithPlayerItem
属于此类。我现在正在寻找一种方法来更改
AVPlayer
的项目而不会出现滞后,但是找不到任何内容。我希望我理解此函数的线程错误,并且有人会纠正我。编辑:
现在,我被告知该调用已被线程化,并且这实际上不应该发生。但是,我没有其他解释。下面是我的
cellForRowAtIndexPath:
。它位于自定义UITableView
中,其委托(delegate)设置为self
(因此self == tableView
)-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [self dequeueReusableCellWithIdentifier:kCellIdentifier];
if(!cell)
cell = [[[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil] objectAtIndex:0];
//Array 'data' contains all objects to be shown. The objects each have titles, url's etc.
CustomVideoObject *currentObject = [data objectAtIndex:indexPath.row];
//When a cell later starts playing, I store a pointer to the cell in this tableView named 'playing'
//After a quick scroll, the dequeueing cell might be the cell currently playing - resetting
if(playing == cell)
playing = nil;
//This call will insert the correct URL, title, etc for the new video, in the custom cell
[cell initializeNewObject:currentObject];
return cell;
}
当前正在“工作”的
initializeNewObject
,但是比较滞后(这在CustomCell.m
内部:-(void)initializeNewObject:(CustomObject*)o
{
//If this cell is being dequeued/re-used, its player might still be playing the old file
[self.player pause];
self.currentObject = o;
/*
//Setting text-variables for title etc. Removed from this post, but by commenting them out in the code, nothing improves.
*/
//Replace the old playerItem in the cell's player
NSURL *url = [NSURL URLWithString:self.currentObject.url];
AVAsset *newAsset = [AVAsset assetWithURL:url];
AVPlayerItem *newItem = [AVPlayerItem playerItemWithAsset:newAsset];
[self.player replaceCurrentItemWithPlayerItem:newItem];
//The last line above, replaceCurrentItemWithPlayerItem:, is the 'bad guy'.
//When commenting that one out, all lag is gone (of course, no videos will be playing either)
//The lag still occurs even if I never call [self.player play], which leads me
//to believe that nothing after this function can cause the lag
self.isPlaying = NO;
}
每次都在完全相同的位置发生延迟。向下快速滚动时,我们可以看到,最底部单元格的顶部到达屏幕中心时会发生短暂的延迟。我想这对您没有任何意义,但是很明显,每次都会在完全相同的位置发生延迟,即当新单元出队时。更改
AVPlayer
的playerItem之后,我什么也没有做 。直到以后我才开始播放视频。 replaceCurrentItemWithPlayerItem:
是,导致此明显的滞后。文档指出它正在另一个线程中更改项目,但是该方法中的某些内容阻碍了我的UI。有人告诉我要使用Instruments中的Time Profiler找出它是什么,但是我不知道该怎么做。通过运行探查器并不时滚动一次, this is the result(图像)。每个图形组的峰值就是我所说的滞后。当我滚动到底部并轻按状态栏滚动到顶部时,(我认为)是一个单一的最高峰。我不知道如何解释结果。我在堆栈中搜索
replace
,发现了 SCSS 。它是从Main Thread
(在顶部)中调用的,这很有意义,“运行时间”为50毫秒,我不知道要考虑什么。图表的相关比例为大约1分钟半的时间跨度。相比之下,在注释掉该单行并再次运行Time Profiler时,图形的峰值显着降低(最高峰值为13%,而图像上的峰值大约为60-70%)。
我不知道要寻找什么。
最佳答案
如果您进行基本的性能分析,我认为您可以缩小问题的范围。对我来说,我遇到了类似的问题,其中replaceCurrentItemWithPlayerItem
阻止了UI线程。我通过检查我的代码来找出哪一行需要时间来解决。对我来说,加载AVAsset很费时间。因此,我使用AVAsset的loadValuesAsynchronouslyForKeys
方法解决了我的问题。
因此,您可以尝试以下方法:
-(void)initializeNewObject:(CustomObject*)o
{
//If this cell is being dequeued/re-used, its player might still be playing the old file
[self.player pause];
self.currentObject = o;
/*
//Setting text-variables for title etc. Removed from this post, but by commenting them out in the code, nothing improves.
*/
//Replace the old playerItem in the cell's player
NSURL *url = [NSURL URLWithString:self.currentObject.url];
AVAsset *newAsset = [AVAsset assetWithURL:url];
[newAsset loadValuesAsynchronouslyForKeys:@[@"duration"] completionHandler:^{
AVPlayerItem *newItem = [AVPlayerItem playerItemWithAsset:newAsset];
[self.player replaceCurrentItemWithPlayerItem:newItem];
}];
//The last line above, replaceCurrentItemWithPlayerItem:, is the 'bad guy'.
//When commenting that one out, all lag is gone (of course, no videos will be playing either)
//The lag still occurs even if I never call [self.player play], which leads me
//to believe that nothing after this function can cause the lag
self.isPlaying = NO;
}