Reputation: 21237
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
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
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