views:

140

answers:

2

I have been messing around with Leaks trying to find which function is not being deallocated (I am still new to this) and could really use some experienced insight.

I have this bit of code that seems to be the culprit. Every time I press the button that calls this code, 32kb of memory is additionally allocated to memory and when the button is released that memory does not get deallocated.

What I found was that everytime that AVAudioPlayer is called to play an m4a file, the final function to parse the m4a file is MP4BoxParser::Initialize() and this in turn allocates 32kb of memory through Cached_DataSource::ReadBytes

My question is, how do I go about deallocating that after it is finished so that it doesn't keep allocating 32kb every time the button is pressed?

Any help you could provide is greatly appreciated!

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

//stop playing
theAudio.stop;


// cancel any pending handleSingleTap messages 
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(handleSingleTap) object:nil];

UITouch* touch = [[event allTouches] anyObject]; 


NSString* filename = [g_AppsList objectAtIndex: [touch view].tag];

NSString *path = [[NSBundle mainBundle] pathForResource: filename ofType:@"m4a"];  
theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];  
theAudio.delegate = self; 
[theAudio prepareToPlay];
[theAudio setNumberOfLoops:-1];
[theAudio setVolume: g_Volume];
[theAudio play];
}
+1  A: 

This line looks culprit to me:

theAudio=[[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path] error:NULL];  

When does this resource get released?

Steve Melvin
+2  A: 

The trick to memory management in Cocoa is to balance out any calls to alloc, retain or copy with a subsequent call to release.

In this case, you are sending alloc to initialize your theAudio variable, but you are never sending release.

Assuming that you will only have one sound playing at a time, the best way to do this is with a property on your controller (the one that has this -touchesBegan method). The property declaration would look like this:

@property (nonatomic, retain) AVAudioPlayer * theAudio;

You will then need to set theAudio to nil in your init method:

theAudio = nil; // note: simple assignment is preferable in init

And be sure to release the variable in your dealloc method:

[theAudio release];

Now, your touchesBegan could look like this:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    //stop playing
    theAudio.stop;
    ...
    AVAudioPlayer * newAudio = [[AVAudioPlayer alloc] initWithContentsOfUrl:...];
    self.theAudio = newAudio; // it is automatically retained here...

    theAudio.delegate = self; 
    [theAudio prepareToPlay];
    [theAudio setNumberOfLoops:-1];
    [theAudio setVolume: g_Volume];
    [theAudio play];

    [newAudio release];       // ...so you can safely release it here
}
e.James
could you explain which `init` method you are referring to? (again, sorry i am very new to this)
iWasRobbed
and also, just to verify I understand this: What you are saying is that I need to load the audio into an additional allocated variable so that I'm not trying to deallocate the current m4a file (or eventually call a deallocated piece of memory)I guess my question is, will `theAudio` still allocate additional memory each time since it isn't being dellocated until `dealloc()` is called?
iWasRobbed
Normally speaking, every controller has both an `-init` and a `dealloc` method. Can I assume that this as a `UIViewController`? If so, the proper method to override is -initWithNibName:bundle: Another alternative is to set your ivar to nil in the `viewDidLoad` method.
e.James
To answer your second question: the line `self.theAudio = newAudio` takes care of a lot of "magic" behind the scenes. It actually calls `dealloc` on the old object before assigning (and retaining) the new one. This ensures that any memory that was allocated for the old instance is freed.
e.James
The final call to `release` in your `dealloc` method is simply there to release the very last object that was stored in the ivar, at the point when your controller itself is released.
e.James
If you're looking for a better understanding of this stuff, Apple has a really good introductory document: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/MemoryMgmt/MemoryMgmt.htmlA lot of the Cocoa questions here on SO involve memory leaks, so it is definitely recommended reading `:)`
e.James
Great, thanks a lot for taking the time to really detail it so I could understand! I got rid of that one and onto a few others now on my own :)
iWasRobbed
Excellent. Glad to hear it!
e.James