ios - 在 UITableView 中更改 AVPlayer 的 playerItem

标签 ios objective-c multithreading cocoa-touch avplayer

我有一个 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;
        }
    }/*...*/
}

运行此程序时,我得到的结果与完全删除替换项目的调用相同。显然,这个函数不能被线程化。
我不完全确定我对此的期望。我想我需要一个干净的 copyAVPlayer为了使它起作用,但经过一番搜索,我发现了几条评论指出 replaceCurrentItemWithPlayerItem:可以不是 在单独的线程中调用,这对我来说毫无意义。我知道 UI 元素不应该在主/UI 线程以外的其他线程中处理,但我永远无法想象 replaceCurrentItemWithPlayerItem属于这一类。

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

编辑:
我现在被告知这个调用已经被线程化了,这不应该真的发生。但是,我没有看到其他解释.. 下面是我的 cellForRowAtIndexPath: .它在自定义 UITableView 中代表设置为 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 需要时间。所以我使用了loadValuesAsynchronouslyForKeys AVAsset 的方法来解决我的问题。

因此,您可以尝试以下方法:

-(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;
}

关于ios - 在 UITableView 中更改 AVPlayer 的 playerItem,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25352155/

相关文章:

java - 将静态 java 对象用于软件组件

ios - 不根据标志执行 objective-c 中的某些代码

ios - 在 UITextView 中编辑文本时添加不同的颜色,而不管 Swift 中的光标位置如何

objective-c - 如何拉伸(stretch) ImageView (iphone dev。)?

调用 openURL 后 iOS 9.3 卡住

iphone - insertNewObjectForEntityForName :inManagedObjectContext: returning NSNumber bug?

ios - 如何知道 NSURLSessionDataTask 响应是否来自缓存?

ios - 没有segue的两个 View Controller 之间的快速委托(delegate)

c++ - 什么时候不应该使用[[carries_dependency]]?

java - 在绘画中使用thread.sleep方法