在UITableView中更改AVPlayer的playerItem

Sti*_*Sti 40 multithreading cocoa-touch objective-c ios avplayer

我有一个UITableView包含滚动时要播放的视频.由于tableView中的单元格正在被重用,我只会AVPlayer为每一行实例化一个.当一个单元被重用时,我只需PlayerItem通过调用来改变单元的播放器[self.player replaceCurrentItemWithPlayerItem:newItem];.目前这是内部间接调用的tableView:cellForRowAtIndexPath.向下滚动时,重新使用时会出现明显的延迟.通过消除过程,我得出结论,滞后是replaceCurrentItemWithPlayerItem在它开始播放之前引起的.当删除这一行代码(阻止播放器获取新视频)时,滞后消失.

我试图解决它:

我有一个UITableViewCell播放这些视频的自定义,我在这些视频中创建了一个方法,用来自对象的新信息进行初始化.IE,在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;
        }
    }/*...*/
}
Run Code Online (Sandbox Code Playgroud)

运行此操作时,我得到的结果与完全删除更换项目的调用相同.显然,这个函数不能被线程化.我不完全确定我对此的期望.我会想象我需要一个干净copyAVPlayer这个工作,但搜索了一下后,我发现了一些意见指出,replaceCurrentItemWithPlayerItem:不能在一个单独的线程,这是没有意义的我被调用.我知道UI元素永远不应该在除main/UI-thread之外的其他线程中处理,但我绝不会想到replaceCurrentItemWithPlayerItem属于这个类别.

我现在正在寻找一种方法来改变一个AVPlayer没有滞后的项目,但找不到任何.我希望我已经理解了这个函数的错误,并且有人会纠正我.

编辑: 我现在已被告知此调用已经线程化,这不应该发生.但是,我没有看到其他解释..下面是我的cellForRowAtIndexPath:.它位于自定义内UITableView,委托设置为self(so 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;
}
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

每次都在完全相同的地方发生滞后.当快速向下滚动时,我们可以看到当最底部单元格的顶部到达屏幕中心时发生短暂滞后.我想这对你没有任何意义,但很明显,每次都在完全相同的地方发生滞后,即当一个新的细胞出列时.更改了playerItem之后AVPlayer,我什么都不做.直到稍后我才开始播放视频.replaceCurrentItemWithPlayerItem: 造成这种明显的滞后.文档声明它正在更改另一个线程中的项目,但该方法中的某些内容正在阻止我的UI.

我被告知要在仪器中使用Time Profiler来查明它是什么,但我不知道该怎么做.通过运行探查器并偶尔滚动一次,这就是结果(图像).每个图组的峰值都是我所说的滞后.当我滚动到底部并点击状态栏滚动到顶部时,单个极端峰值(我认为).我不知道如何解释结果.我搜索了堆栈replace,找到了这个混蛋.它从内部Main Thread(在顶部)调用,这是有意义的,50ms的"运行时间",我不知道这一点.图的相关比例是约1分半的时间跨度.相比之下,当评论该单行并再次运行Time Profiler时,图形的峰值显着降低(最高峰值为13%,与图像上的峰值相比,可能约为60-70%).

我不知道该找什么..

Dim*_*ima -1

您应该使用时间分析器来分析您的应用程序,以查看实际发生滞后的位置。

的文档replaceCurrentItemWithPlayerItem:明确指出它是异步执行的,因此它不应该成为主队列跳跃的根源。

物品替换是异步发生的;观察 currentItem 属性以了解何时将/确实发生替换。

文档在这里

如果您仍然无法弄清楚,请发布更多代码,特别是至少您的cellForRowAtIndexPath方法。

更新

根据@joey下面的评论,该答案之前的内容不再有效。文档不再声明该方法是异步的,因此可能不是。