3

こんにちは、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;


   }

何が原因でしょうか? この SO の質問を確認しましたが、これをコードに実装できませんでした。これを修正するのを手伝ってください。

4

1 に答える 1

4

私の経験では、オブザーバーの削除は iOS で最も不安定な領域の 1 つです。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 を渡します

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

これ以上のコードがなければ、これをより詳細に指定することはできません。また、コードを最初に xcode でフォーマットしてから、カット アンド ペーストして SO に貼り付けて整理することも考えられます。

于 2015-01-09T08:16:09.650 に答える