AVPlayers в UICollectionViewCells в конечном итоге приводят к сбою приложения после прокрутки

Я пытаюсь создать приложение, похожее на Vine, где это просто поток ячеек, а видео воспроизводится автоматически, когда вы прокручиваете и останавливаетесь на ячейке.

У каждого UICollectionViewCell есть свой AVPlayer.

Прямо сейчас моя текущая настройка по большей части работает нормально, но после прокрутки некоторое время приложение в конечном итоге падает, и мой аналитический SDK показывает, что сбой вызван следующей ошибкой:

An AVPlayerItem cannot be associated with more than one instance of AVPlayer

Приложение также иногда падает сразу после того, как я получаю предупреждение о памяти в консоли.

У меня есть ощущение, что это связано с тем, как я настраиваю AVPlayers для каждого UICollectionViewCell, и как повторно используются ячейки, но я не совсем уверен.

Вот код, который у меня есть в моем контроллере представления, который касается настройки ячеек и их AVPlayers:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{

   MyCollectionViewCellSubclass *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
   [cell load:self.objectsFromServer[indexPath.row] withBannerColor:self.bannerColors[indexPath.row % self.bannerColors.count]];

   QBCOCustomObject *objectFromServer = self.objectsFromServer[indexPath.row];

   NSURL *videoURL = [NSURL URLWithString:objectFromServer.fields[@"Video_URL"]];

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);

    dispatch_async(queue, ^{
        cell.playerItem = [AVPlayerItem playerItemWithURL:videoURL];

        dispatch_sync(dispatch_get_main_queue(), ^{

            cell.player = [AVPlayer playerWithPlayerItem:cell.playerItem];
            cell.playerLayer = [AVPlayerLayer playerLayerWithPlayer:cell.player];
            cell.playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;

            cell.player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
            cell.playerLayer.frame = CGRectMake(0, 0, 320, 186.5);
            [cell.banner.layer addSublayer:cell.playerLayer];

        });
    });

}
  return cell;
}

Я использую scrollViewDidScroll: для воспроизведения/приостановки ячеек. Я проверяю, чтобы убедиться, что текущая видимая ячейка не является последней ячейкой lastPlayingCell/той, которая воспроизводит видео, и если это не так, то я приостанавливаю lastPlayingCell и воспроизводю видео видимой ячейки.

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{ 

// Play/Pause Video
CGRect visibleRect = (CGRect){.origin = self.collectionView.contentOffset, .size = self.collectionView.bounds.size};
CGPoint visiblePoint = CGPointMake(CGRectGetMidX(visibleRect), CGRectGetMidY(visibleRect));
NSIndexPath *visibleIndexPath = [self.collectionView indexPathForItemAtPoint:visiblePoint];
NSLog(@"%@",visibleIndexPath);

MyCollectionViewCellSubclass *cell = (MyCollectionViewCellSubclass *)[self.collectionView cellForItemAtIndexPath:visibleIndexPath];

if (cell != self.lastPlayingCell) {

    [self.lastPlayingCell pauseVideo];
    self.lastPlayingCell = cell;
    [cell playVideo];
  }
}

person user3344977    schedule 09.04.2015    source источник
comment
У меня есть что-то похожее, но вместо автоматического воспроизведения видео в моем приложении воспроизводится по клику, поэтому не могли бы вы поделиться со мной, как AVPlayer реализован внутри CollectionViewCell   -  person Chlebta    schedule 29.10.2015


Ответы (1)


Эта строка, [cell.banner.layer addSublayer:cell.playerLayer]; будет добавлять новый playerLayer всякий раз, когда ячейка используется повторно. Вам нужно проверить, есть ли в ячейке уже игрок, прежде чем добавлять его. Если он уже есть, используйте replaceCurrentItemWithPlayerItem:, чтобы дать игроку новый AVPlayerItem.

person rdelmar    schedule 09.04.2015
comment
Итак, я должен проверить, есть ли в ячейке игрок, если да, то я НЕ должен добавлять cell.playerLayer, а также должен использовать replaceCurrentItemWithPlayerItem:? - person user3344977; 09.04.2015
comment
@ user3344977, да, я так думаю. - person rdelmar; 09.04.2015
comment
Ваше решение работает отлично и решило проблему. Спасибо, что нашли время помочь! - person user3344977; 09.04.2015
comment
@rdelmar: я попробовал ваше решение, но ячейка повторного использования не может воспроизводить видео. Это мой исходный код: BOOL isFound = NO; for (AVPlayerLayer *layer in cell.playerView.layer.sublayers) { if ([layer isKindOfClass:[класс AVPlayerLayer]]) { isFound = YES; ломать; } } if (!isFound) { [cell.playerView.layer addSublayer:cell.playerLayer]; } else{ [cell.player replaceCurrentItemWithPlayerItem:cell.playerItem]; } - person NTNT; 27.07.2016