本文介绍了iOS8中的AVPlayerItem addobserver问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用AVPlayer在UITableViewCells上播放视频,在iOS 7上运行正常,但是在iOS8上,它崩溃并出现以下错误.

Hi I am playing video on my UITableViewCells using AVPlayer, It was working fine on iOS 7, but in iOS8 it crashing with following error.

       '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;


   }

可能是什么原因?我已经解决了这个SO问题,但是无法在代码中实现.请帮我解决这个问题.

What could be the reason ? I have gone through this SO question, but I could not implement this in my codes. Please help me to fix this.

推荐答案

以我的经验,移除观察者是iOS中最脆弱的领域之一.您需要非常小心地平衡对RemoveObserver和AddObserver的调用.我发现执行此操作的故障安全方法是将所有AddObserver调用放入对象的Init方法中,然后在其Dealloc方法中将它们与RemoveObserver调用进行平衡.在您的情况下,这将在您的"videoItem"子类中. (此代码未选中)

Removing observers is one of the flakiest areas in iOS in my experience. You need to balance calls for AddObserver with a RemoveObserver very carefully. I have found a failsafe way to do this is to put any AddObserver calls into an object's Init method and then balance these with RemoveObserver calls in its Dealloc method. In your case this would be in your 'videoItem' subclass. (this code is not checked)

- (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实例,并以所有者身份自我传递

I'm not sure where videoItem is declared but basically you create a new class called VideoItem and in it create a new initialiser called initWithOwner:. In your cellForRowAtIndexPath: method when you create your new cell you also create an instance of VideoItem and pass in self as the owner

self.videoItem = [[VideoItem alloc] initWithOwner:self];

如果没有更多的代码,我真的无法更详细地指定.您可能还会想到先在xcode中格式化代码,然后将其剪切并粘贴到SO中以保持整洁.

Without more of your code I can't really specify this in more detail. You might also think of formatting your code first in xcode then cutting and pasting it into SO to keep it tidier.

这篇关于iOS8中的AVPlayerItem addobserver问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-23 15:33