AVAudioPlayer Memory Leak
While coding the sound for Arctic Shuffle 2, I ran into a non-obvious memory (to me, anyway) memory leak related to the AVAudioPlayer that took forever to track down.
Here was my original code, which leaks if an error occurs in the initWithData:error: method:
- (AVAudioPlayer *)audioPlayerWithContentsOfFile:(NSString *)path { NSData *data = [NSData dataWithContentsOfFile:path]; return [[[AVAudioPlayer alloc] initWithData:audioData error:NULL] autorelease]; }
If an error occurs in the initWithData:error: method (say because the file is missing), it returns nil. If it returns nil, autorelease gets called on nil, not on the AVAudioPlayer object, and the AVAudioPlayer object gets leaked.
Here’s the leak-free version:
- (AVAudioPlayer *)audioPlayerWithContentsOfFile:(NSString *)path { NSData *data = [NSData dataWithContentsOfFile:path]; AVAudioPlayer *player = [AVAudioPlayer alloc]; if([player initWithData:audioData error:NULL]) { [player autorelease]; } else { [player release]; player = nil; } return player; }
The leak-free version stores the pointer returned by alloc, rather than the pointer returned by initWithData:error:. That way, whatever happens, the player can still be released.
June 3rd, 2009 at 5:45 pm
Thanks for this, you saved me and countless others a bunch of time!
August 24th, 2009 at 6:13 am
Hi Luke can u post full application. When i use ur function
audioPlayerWithContentsOfFile:(NSString *)path no leak. But i am unable to hear any sound. I commented [player release] and [player autorelease]. Then i am able to hear sound but same memory leak.
Could you please solve my problem.
Thanks
shiva
August 24th, 2009 at 10:01 am
@shiva: You just need to retain the AVAudioPlayer object returned by audioPlayerWithContentsOfFile:
AVAudioPlayer *player = [someObject audioPlayerWithContentsOfFile:@"someFile.caf"];
[player retain];
And then release it when you’re done with it :-)
August 27th, 2009 at 2:25 am
Still i am getting leak.
I am using more than one sound file.
When even new image scrolls onto view, i am playing different sound
Could you please help me?
Thanks
shiva
July 14th, 2010 at 1:21 pm
>>> player initWithData:audioData
Don’t you mean data since you said NSData *data = …
And don’t you have to release that too?
September 3rd, 2010 at 9:59 am
Not solved entirely the problems on my App, but your trick is a BIG step ahead!
Before my Intro animated with sounds crashed after 3 times you launch on buggy iOs 4.02 with iPhone 3G (worst environment), now lasts 6 time !
October 13th, 2010 at 4:11 pm
Someone (you?) posted your code on StackOverflow:
http://stackoverflow.com/questions/2124622/trying-to-fix-memory-leak-using-avaudioplayer
…and got told that it’s pretty crappy altogether…
October 14th, 2010 at 8:00 am
@Gene De Lisa: The NSData object returned by [NSData dataWithContentsOfFile:] is already auto-released.
@zmip: The code posted on Stack Overflow doesn’t mention that it’s written that way to work around a problem caused by calling alloc and init on the same line. I realize that what I’m suggesting isn’t the standard way to allocate and initialize an object, but it was necessary to get rid of the memory leak I had.
December 23rd, 2010 at 1:43 pm
thanks. this saved my christmas.
May 23rd, 2011 at 9:21 am
@Luke:
Regarding zmip’s link, I posted a link to this article on that StackOverflow answer, to provide people context.