I am runung Instruments on an iPhone 4S. I am using AVAudioPlayer inside this method:
-(void)playSound{
NSURL *url = [self.word soundURL];
NSError *error;
audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
if (!error) {
[audioPlayer prepareToPlay];
[audioPlayer play];
}else{
NSLog(@"Problem With audioPlayer on general card. error : %@ | url %@",[error description],[url absoluteString]);
}
I am getting leaks when playing the sound files:
Leaked objects:
1.
Object: NSURL
Responsible Library: Foundation
Responsable Frame: Foundation -[NSURL(NSURL) allocWithZone:]
2.
Object: _NSCFString
Responsible Library: Foundation
Responsable Frame: Foundation -[NSURL(NSURL) initFileURLWithPath:]
Instruments does not point directly to my code so I find it hard to locate the leak reason.
MY QUESTION
What could cause the leak? OR How can I locate leaks when I am not responsible to the code?
EDIT This is the schema from Instruments cycles view: Thanks Shani
Looks to be a leak in Apple's code... I tried using both
-[AVAudioPlayer initWithData:error:]
and -[AVAudioPlayer initWithContentsOfURL:error:]
In the first case, the allocated AVAudioPlayer
instance retains the passed in NSData
. In the second, the passed in NSURL
is retained:
I've attached some screen shots of the Instruments window showing the retain/release history for a passed in NSData
object.
You can see the AVAudioPlayer
object then creates a C++ object AVAudioPlayerCpp
, which retains the NSData again:
Later, when the AVAudioPlayer
object is released, the NSData
is released, but there's never a release call from the associated AVAudioPlayerCpp
... (You can tell from the attached image)
Seems you'll have to use a different solution to play media if you want to avoid leaking NSData/NSURL's..
Here's my test code:
-(void)timerFired:(NSTimer*)timer
{
NSString * path = [[ NSBundle mainBundle ] pathForResource:@"song" ofType:@"mp3" ] ;
NSError * error = nil ;
NSData * data = [ NSData dataWithContentsOfFile:path options:NSDataReadingMapped error:&error ] ;
if ( !data )
{
if ( error ) { @throw error ; }
}
AVAudioPlayer * audioPlayer = data ? [[AVAudioPlayer alloc] initWithData:data error:&error ] : nil ;
if ( !audioPlayer )
{
if ( error ) { @throw error ; }
}
if ( audioPlayer )
{
[audioPlayer play];
[ NSThread sleepForTimeInterval:0.75 ] ;
[ audioPlayer stop ] ;
}
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
[ NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector( timerFired: ) userInfo:nil repeats:YES ] ;
// ...
return YES;
}