您好我正在使用AVPlayer在我的UITableViewCells上播放视频,它在iOS 7上工作正常,但在iOS8中它崩溃并出现以下错误。
'An instance 0x7c01b000 of class AVPlayerItem was deallocated while key value observers were still registered with it.
这是我的代码
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
.........
.........
if(cell.videoPlayer!= nil && cell.videoPlayer.currentItem != nil)
{
[cell.videoItem removeObserver:self forKeyPath:@"playbackBufferEmpty" context:nil];
[cell.videoItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp" context:nil];
}
cell.videoPlayer = [AVPlayer playerWithPlayerItem:cell.videoItem];
cell.avLayer = [AVPlayerLayer playerLayerWithPlayer:cell.videoPlayer];
cell.videoPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
[cell.videoItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionInitial context:nil];
[cell.videoItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionInitial context:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidBufferPlaying:) name:AVPlayerItemPlaybackStalledNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(itemDidFinishPlaying:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
cell.avLayer.frame = CGRectMake(5, 9, 310, 310);
[cell.contentView.layer addSublayer: cell.avLayer];
[ cell.videoPlayer play];
[cell.contentView addSubview:cell.videoActivity];
return cell;
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
NSArray* cells = homeTabl.visibleCells;
for (HomeCell* cell in cells) {
if (object == cell.videoItem && [keyPath isEqualToString:@"playbackBufferEmpty"]) {
if (cell.videoItem.playbackBufferEmpty) {
NSLog(@"buffering");
cell.videoActivity.hidden = NO;
}
}
else if (object == cell.videoItem && [keyPath isEqualToString:@"playbackLikelyToKeepUp"])
{
if (cell.videoItem.playbackLikelyToKeepUp)
{
cell.videoActivity.hidden = YES;
[cell.videoPlayer play];
}
}
}
}
-(void)scrollViewDidScroll:(UIScrollView *)aScrollView {
NSArray* cells = homeTabl.visibleCells;
for (HomeCell* cell in cells) {
[cell.videoPlayer pause];
[cell.avLayer removeFromSuperlayer];
cell.videoPlayer = nil;
cell.videoItem = nil;
}
可能是什么原因?我已经解决了这个问题,但我无法在我的代码中实现这一点。请帮我解决这个问题。
答案 0 :(得分:4)
根据我的经验,删除观察者是iOS中最脆弱的领域之一。您需要非常小心地平衡AddObserver与RemoveObserver的调用。我发现一种故障安全的方法是将任何AddObserver调用放入对象的Init方法中,然后在Dealloc方法中使用RemoveObserver调用来平衡它们。在你的情况下,这将在你的'videoItem'子类中。 (未检查此代码)
- (id) initWithOwner:(id)owner
{
self = [super init];
if( self ) {
_owner = owner;
[self addObserver:_owner forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionInitial context:nil];
}
return self;
}
- (void) dealloc
{
[self removeObserver:_owner forKeyPath:@"playbackBufferEmpty" context:nil];
}
我不确定videoItem的声明位置,但基本上你创建了一个名为VideoItem的新类,并在其中创建一个名为initWithOwner的新初始化器:在您的cellForRowAtIndexPath:方法中,当您创建新单元格时,您还可以创建一个VideoItem实例并以自己的身份传入自己
self.videoItem = [[VideoItem alloc] initWithOwner:self];
如果没有更多代码,我无法更详细地说明这一点。您可能还会考虑先在xcode中格式化代码,然后将其剪切并粘贴到SO中以保持其更整洁。