0
votes

I posted a much longer question a few minutes ago, and as it usually goes as soon as I posted it I realized what was going on, so I deleted it since most of the post was irrelevant. Then I went back to Google.

Turns out I'm having almost the same exact problem as described in this post, unanswered from June. http://www.iphonedevsdk.com/forum/iphone-sdk-development/20975-avaudioplayer-nsurl-memory-management.html

In summary: I'm using AVAudioPlayer and releasing it with the audioPlayerDidFinishPlaying:successfully: delegate method. After I initialize the player, its associated NSURL object needs to be freed, otherwise it leaks. But when I release it after initializing the player, it crashes since it has already been freed. The weird thing is that it doesn't always crash the first time, most of the time it crashes after the second sound has been played. Sometimes (rarely) it will allow a handful or players to be alloc/released (I reuse the pointers after freeing) before crashing. Any help?

Code snippet: (soundKeyUp is an AVAudioPlayer* class variable, hence no declaration here)

NSString *soundKeyUpPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"soundKeyUp%d", key.tag % 5] ofType:@"wav"];
    NSURL *soundKeyUpURL = [[NSURL alloc] initFileURLWithPath:soundKeyUpPath];
    soundKeyUp = [[AVAudioPlayer alloc] initWithContentsOfURL:soundKeyUpURL error:nil];
    if(soundKeyUp) {
        [soundKeyUp setDelegate:self];
        [soundKeyUp play];
    }
    else {
        [soundKeyUp release];
        soundKeyUp = nil;
    }

    [soundKeyUpPath release];
    [soundKeyUpURL release];

Response to Steve Riggins: The trick of it is that it doesn't crash at the same time every time, as mentioned. It almost always properly releases the first time (or at least, it doesn't crash or leak) but usually after the second time I allocate/release the player and URL, it crashes on releasing the URL. Sometimes, it goes 3, 4, 5+ times before crashing, but it always does.

2

2 Answers

1
votes

Release the URL when you create the player. I do this in my app and it functions fine. No leaks, crashes, etc

AVAudioPlayer *newPlayer =
        [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                                               error: nil];
        [fileURL release];

And never, ever release objects that are contained by other objects. That is their job, not yours.

Edit: If your url is still leaking, you need to look at what you're doing when you create it. It should be something like:

NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: [self path]];

Following the Cocoa rules of ownership, using an alloc method means you own it, so you release it.

0
votes
 - (IBAction) playaction {

        NSString *soundFilePath = [[NSBundle mainBundle] pathForResource:@"songname" ofType:@"mp3"];
        NSURL *newURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
        self.soundFileURL = newURL;
        [newURL release];
        [[AVAudioSession sharedInstance] setDelegate: self];
        [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: nil];

    // Registers the audio route change listener callback function
    AudioSessionAddPropertyListener (
                                     kAudioSessionProperty_AudioRouteChange,
                                     audioRouteChangeListenerCallback,
                                     self
                                     );

    // Activates the audio session.

    NSError *activationError = nil;
    [[AVAudioSession sharedInstance] setActive: YES error: &activationError];

    AVAudioPlayer *newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: soundFileURL error: nil];
    self.appSoundPlayer = newPlayer;
    [newPlayer release];
    [appSoundPlayer prepareToPlay];
    [appSoundPlayer setVolume: 1.0];
    [appSoundPlayer setDelegate: self];
    [appSoundPlayer play];

}

You will be required to use something similar to this. Here appSoundPlayer is declared in the header file as

AVAudioPlayer *appSoundPlayer;

Also set property to it,

@property(nonatomic, retain)AVAudioPlayer *appSoundPlayer;

Release it in the dealloc method.. This is the method i'm following and haven't seen any memory leaks