AVPlayerItem addobserver issue in iOS8
Asked Answered
R

1

3

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.

Here is my code

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


   }

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.

Radnorshire answered 8/1, 2015 at 10:53 Comment(0)
L
4

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];
}

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

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.

Lamarre answered 9/1, 2015 at 8:16 Comment(2)
Hi @Lamarre - Thanks for your help. Can you please describe a little more, where do I use the above code. I declared VideoItem in my Table cell. Can you please check with my code.Radnorshire
@NITHINSHAHRUKH edited my answer a bit. Without more of your code I cannot be any clearer, sorry.Lamarre

© 2022 - 2024 — McMap. All rights reserved.