AVAudioPlayer memory leak

10,540

Solution 1

Here is method to create AVAudioPlayer without causing memory leaks. See this page for explaination.

I have confirmed in my app that this removed my AVAudioPlayer leaks 100%.

- (AVAudioPlayer *)audioPlayerWithContentsOfFile:(NSString *)path {
    NSData *audioData = [NSData dataWithContentsOfFile:path];
    AVAudioPlayer *player = [AVAudioPlayer alloc];
    if([player initWithData:audioData error:NULL]) {
        [player autorelease];
    } else {
        [player release];
        player = nil;
    }
    return player;
}

Solution 2

Implement the protocol AVAudioPlayerDelegate and its method audioPlayerDidFinishPlaying:successfully: then release the audio player object

eg.

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
    [player release]; // releases the player object
}
Share:
10,540
Adi
Author by

Adi

Updated on July 01, 2022

Comments

  • Adi
    Adi almost 2 years

    I'm stuck on some weird memory leak problem related to the AVAudioPlayer and I need help after trying everything that came to mind.

    Here is the short description of the problem - code appears right after. I initialize my player and start to play the sound track in an endless loop (and endless loop or one time play did not change the problem). Several seconds after the music started, I switch to another sound track, hence I create a new player, initialize it, release the old one (which is playing) and then set the new one in place and play it.

    At that point in time (right after I call the new Player - [Player play]) I get a memory leak (of 3.5Kb).

    I tried the following:

    • Stop the old player and then release it - no effect

    • Release the Player right after the play instruction - did not start playing

    • Release twice the old player - crash

    • Memory leak DOES NOT happen when I create and play the first Player!

    Also, in the reference it does say that the 'play' is async and so probably it increases the ref count by 1, but in this case, why didn't [Player stop] help?

    Thanks,

    Here are some parts of the code about how I use it:

    - (void) loadAndActivateAudioFunction {
    NSBundle        *mainBundle = [NSBundle mainBundle];
    NSError         *error;
    NSURL           *audioURL = [NSURL fileURLWithPath:[mainBundle pathForResource: Name ofType: Type]];
    AVAudioPlayer   *player = [(AVAudioPlayer*) [AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
    
    if (!player) {
        DebugLog(@"Audio Load Error: no Player: %@", [error localizedDescription]);
        DuringAudioPrep = false;
        return;
    }
    [self lock];
    [self setAudioPlayer: player];
    [self ActivateAudioFunction];
    [self unlock];
    

    }

    - (void) setAudioPlayer : (AVAudioPlayer *) player {
    if (Player)
    {
        if ([Player isPlaying] || Repeat)  // The indication was off???
            [Player stop];
        [Player release];
    }
    Player = player;
    

    }

    - (void) ActivateAudioFunction {
    [Player setVolume: Volume];
    [Player setNumberOfLoops: Repeat];    
    [Player play];
    
    DuringAudioPrep = false;
    

    }

  • Adi
    Adi over 14 years
    Thanks for the answer. Yes - I verified that it is the AVAudioPlayer with Instruments. As to the method - I use this one because I actually save the different tracks and reuse them by matching names and if they are not playing (instead of downloading the same track several times). Since I know that I get the Player from the caller after doing an 'Alloc' on it, I know that it is already retained (unless I got it wrong?)
  • Ivan Vučica
    Ivan Vučica almost 13 years
    MediaPlayer.framework? AVAudioPlayer is located in AVFoundation.framework and should not require MediaPlayer. Care to elaborate?
  • MoDJ
    MoDJ almost 11 years
    This code is really odd, there is no reason to split out the alloc vs init calls. For a better general approach, see stackoverflow.com/questions/17603551/arc-forbids-autorelease‌​/… or you can just add autorelease in like [[[AVAudioPlayer alloc] initWithData:audioData error:NULL] autorelease]