AVPlayers в UICollectionViewCells в крайна сметка се срива в приложението след превъртане

Опитвам се да създам приложение, подобно на Vine, където то е просто емисия от клетки и видеоклиповете се пускат автоматично, когато превъртите и спрете върху клетка.

Всеки UICollectionViewCell има свой собствен AVPlayer.

В момента текущата ми настройка работи добре в по-голямата си част, но след превъртане известно време приложението в крайна сметка се срива и моят SDK за анализ показва, че сривът е причинен от следната грешка:

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

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

Имам чувството, че това е свързано с това как настройвам AVPlayers за всеки UICollectionViewCell и как клетките се използват повторно, но не съм напълно сигурен.

Ето кода, който имам досега в моя View Controller, който се занимава с настройването на клетките и техните 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; за (AVPlayerLayer *слой в cell.playerView.layer.sublayers) { if ([layer isKindOfClass:[AVPlayerLayer class]]) { isFound = YES; прекъсване; } } if (!isFound) { [cell.playerView.layer addSublayer:cell.playerLayer]; } else{ [cell.player replaceCurrentItemWithPlayerItem:cell.playerItem]; } - person NTNT; 27.07.2016