AndroidDev
AndroidDev

Reputation: 21237

Instance of class AVPlayer was deallocated

I have a UIView that responds to a single tap gesture by playing an audio file. It does this by using the AVPlayer class. It all works well with one exception. If a user is currently listening to an audio file, and they tap the same UIView again, I want the audio file to return to the beginning and start playing again from the start. However, when this occurs, I get the following console output:

An instance 0x10ad89dd0 of class AVPlayer was deallocated while key value observers were still registered with it. Observation info was leaked, and may even become mistakenly attached to some other object.

The first three lines in my play method are my attempt to deal with this, but they don't solve anything. The audio does restart, but the controls (time played, sliders, etc) all go crazy. I see a couple of other posts on this, I'm still stuck. Can anyone see what I need to do to clear this problem?

- (void) playAudio : (UITapGestureRecognizer *)recognizer
{

    // remove any existing observers to prevent memory leaks
    [self.audioPlayer pause];
    self.audioPlayer = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self name:AVPlayerItemDidPlayToEndTimeNotification object:self.audioPlayer];

    unsigned long buttonPressed = [self.buttonsArray indexOfObject:recognizer.view];

    Sessions *session = self.sessionsList[buttonPressed];
    self.mediaFile  = session.media_file;
    self.totalSecondsToPlay = [session.play_seconds integerValue];

    [self resetAVControls];

    NSString *urlString = [NSString stringWithFormat:@"%@%@", AUDIO_URL, self.mediaFile];
    AVPlayer *player = [[AVPlayer alloc]initWithURL:[NSURL URLWithString:urlString]];

    self.audioPlayer = player;

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(playerItemDidReachEnd:)
                                                 name:AVPlayerItemDidPlayToEndTimeNotification
                                               object:[self.audioPlayer currentItem]];

    [self.audioPlayer addObserver:self forKeyPath:@"status" options:0 context:nil];

    self.isPlaying = YES;

    timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                     target:self
                                   selector:@selector(updateProgress)
                                   userInfo:nil
                                    repeats:YES];


}

Upvotes: 0

Views: 2326

Answers (2)

jose920405
jose920405

Reputation: 8057

Each time when your set your playerview to nil, before call removeObserver.

Example

[self removeObserverForStatusPlay];
playerView = nil;

And before Init

[self removeObserverForStatusPlay];
playerView = [[AVPlayer alloc] initWithURL:url];

When removeObserverForStatusPlay method is

- (void)removeObserverForStatusPlay
{
    @try {
        [playerView removeObserver:self forKeyPath:@"status"];
    } @catch(id anException) {
        NSLog(@"excepcion remove observer == %@. Remove previously or never added observer.",anException);
        //do nothing, obviously it wasn't attached because an exception was thrown
    }
}

Upvotes: 0

bhargavg
bhargavg

Reputation: 1379

You've registered KeyValueObservers for self.audioPlayer, but you haven't removed them when you are setting the value to nil. So before doing self.audioPlayer = nil; unsubscribe to KVO by using [self.audioPlayer removeObserver:self forKeyPath:@"status" context:nil]

Check this if you want to know more about KVO

Upvotes: 3

Related Questions