UICollectionViewCells 中的 AVPlayers 在滚动后最终导致应用程序崩溃
AVPlayers in UICollectionViewCells eventually crash app after scrolling
我正在尝试创建一个类似于 Vine 的应用程序,它只是一个单元格的提要,当您滚动并停在一个单元格上时,视频会自动播放。
每个 UICollectionViewCell
都有自己的 AVPlayer
。
现在,我当前的设置大部分都可以正常工作,但在滚动一段时间后,应用程序最终崩溃了,我的分析 SDK 显示崩溃是由以下错误引起的:
An AVPlayerItem cannot be associated with more than one instance of AVPlayer
我在控制台收到内存警告后,应用有时也会崩溃。
我觉得这与我如何为每个 UICollectionViewCell
设置 AVPlayers
以及如何重复使用单元格有关,但我不完全确定。
这是我目前在我的视图控制器中处理设置单元格及其 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:
来处理 playing/pausing 个单元格。我检查以确保当前可见的单元格不是 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];
}
}
这一行,[cell.banner.layer addSublayer:cell.playerLayer]
;每当重复使用单元格时,都会添加一个新的 playerLayer。在添加一个之前,您需要检查单元格是否已经有一个播放器。如果已经有了,使用 replaceCurrentItemWithPlayerItem:
给玩家一个新的 AVPlayerItem
.
我正在尝试创建一个类似于 Vine 的应用程序,它只是一个单元格的提要,当您滚动并停在一个单元格上时,视频会自动播放。
每个 UICollectionViewCell
都有自己的 AVPlayer
。
现在,我当前的设置大部分都可以正常工作,但在滚动一段时间后,应用程序最终崩溃了,我的分析 SDK 显示崩溃是由以下错误引起的:
An AVPlayerItem cannot be associated with more than one instance of AVPlayer
我在控制台收到内存警告后,应用有时也会崩溃。
我觉得这与我如何为每个 UICollectionViewCell
设置 AVPlayers
以及如何重复使用单元格有关,但我不完全确定。
这是我目前在我的视图控制器中处理设置单元格及其 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:
来处理 playing/pausing 个单元格。我检查以确保当前可见的单元格不是 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];
}
}
这一行,[cell.banner.layer addSublayer:cell.playerLayer]
;每当重复使用单元格时,都会添加一个新的 playerLayer。在添加一个之前,您需要检查单元格是否已经有一个播放器。如果已经有了,使用 replaceCurrentItemWithPlayerItem:
给玩家一个新的 AVPlayerItem
.