Conor Taylor
Conor Taylor

Reputation: 3108

AVAudioPlayer memory leaks

I have this method in an exterior class that gets called whenever the charachter in my game hits a wall (about once every 5 seconds on average). I dont understand it. I thaught I was on top of the memory management. Everytime the method is called, a small amount of memory is leaked (Malloc 38 or 42 bytes) This keeps happening, and the game freezes up. Here is my code:

-(void)playBoing {
    int x = (arc4random()%3)+1;
    NSString *path = [NSString stringWithFormat:@"/boing_0%i.aif", x];

    NSString* resourcePath = [[NSBundle mainBundle] resourcePath];
    resourcePath = [resourcePath stringByAppendingString:path];

    if (boing != nil) {
        boing = nil;
        boing.delegate = nil;
        [boing release];
    }
    boing = [[AVAudioPlayer alloc] initWithContentsOfURL:
             [NSURL fileURLWithPath:resourcePath] error:nil];

    boing.delegate = self;
    boing.volume = 1;
    [boing play];
}

Upvotes: 0

Views: 1446

Answers (2)

5hrp
5hrp

Reputation: 2230

Of course, it's lead to memory leak

First you said, that boing is nil (but memory is not deallocated, leaked), then trying to send release message to nil. You should do it like this:

[boing release];
boing = [[AVAudioPlayer alloc] initWithContentsOfURL:
             [NSURL fileURLWithPath:resourcePath] error:nil];

No need to check boing for nil before releasing, because sending message to nil do nothing

Upvotes: 1

Jhaliya - Praveen Sharma
Jhaliya - Praveen Sharma

Reputation: 31722

I think, the below statement is the source of memory leak,

player = [[AVAudioPlayer alloc] initWithContentsOfURL:file error:&err];

Here is the SO posts which has discussed the same issue.

AVAudioPlayer memory leak

AVAudioPlayer memory leak

AVAudioPlayer Memory Leak - Media Player Framework

Here is the blog post

AVAudioPlayer Memory Leak

As per the blog tutorial your code must be look like below.

-(void)setPlayer
{

    NSURL *file = [[NSURL alloc] initFileURLWithPath:
                   [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"shut up.mp3"]];
    NSError *err = nil;

    NSData *data = [NSData dataWithContentsOfFile:file];
    AVAudioPlayer *player = [AVAudioPlayer alloc];    
    if([player initWithData:audioData error:NULL])
     {

        player.numberOfLoops = -1;
        [player prepareToPlay];
        player.volume=1.0;
        [player autorelease];
    } 
    else 
    {
        [player release];
        player = nil;
    }
    [file release];
}

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.

Upvotes: 1

Related Questions