Should I release NSBundle in the below code or not? NSURL should also be release or not?
I am confused.
NSBundle *mainBundle = [NSBundle mainBundle];
NSError *error;
NSURL *audioURL = [NSURL fileURLWithPath:[mainBundle pathForResource:#"count_in" ofType: #"mp3"]];
AVAudioPlayer *player1 = [(AVAudioPlayer*) [AVAudioPlayer alloc] initWithContentsOfURL:audioURL error:&error];
self.player = player1;
[self.player play];
[player1 release];
You should not release NSBundle and NSURL instances because you haven't alloced these.
From the apple Documentation.
You take ownership of an object if you create it using a method whose
name begins with “alloc”, “new”,
“copy”, or “mutableCopy” (for example,
alloc, newObject, or mutableCopy), or
if you send it a retain message.
You use release or autorelease to relinquish ownership of an object.
autorelease just means “send a release
message in the future” (specifically:
when the used autorelease pool
receives a drain message—to understand
when this will be, see “Autorelease
Pools”).
I would highly recommend you to clear your memory management concept.
Read the apple article on
Memory Management Rules
Related
I am asking just logical question. Will object be released from memory if I release pool first and then release the object ? For example, here is my code snippet:
[self performSelectorInBackground:#selector(setImage) withObject:nil];
-(void)setImage
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
NSString *strUrl = #"--some URL--";
NSData *imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:strUrl]];
UIImage *myimage = [[UIImage alloc] initWithData:imageData];
[pool release];
[imageData release];
}
Assume that the code snippet executes under non-ARC environment.
This will be fine as you never added the imageData object to the autorelease pool, so the pool won't release it. If you had added the imageData object to the autorelease pool like this:
[[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:strUrl]] autorelease];
The extra release would be an overrelease and your app may crash.
It looks like you've leaked myImage as this is never released.
when you call [pool release]; immediate deallocation wont happen to the autorelease objects that are added to the pool. So when you explicitly call release your imageData's reference count would reduce by 1. When pool releases either application would crash with deallocated instance or message sent to nil object.
I am working on a basic game, that connects to a server and gets JSON data. It works fine for a few games, but crashes soon after due to memory pressure. I ran through instruments and came across something rather disturbing. Almost every instance variable being instantiated by [[Class alloc]init] was being leaked as a NSZombie object.
As you can see in the image, in 5 seconds I seem to have generated 9000 leaks.
I am using ARC.
Further analysis showed I was leaking when used certain methods:
-(void) playTimeUp
{
NSURL *url = [NSURL fileURLWithPath:[[NSBundle mainBundle]
pathForResource:#"Gameover"
ofType:#"wav"]];
AVAudioPlayer *audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
if (audioPlayer && soundShouldPlay){
[audioPlayer setDelegate:self];
[audioPlayer prepareToPlay];
[audioPlayer setVolume:.20];
[audioPlayer play];
[self.audioPlayers addObject:audioPlayer];
}
}
Also I use dataWithContentsOfUrl method quite often.
dispatch_async(kBackgroundQueue, ^{
NSData* data = [NSData dataWithContentsOfURL:completeUrl];
[self performSelectorOnMainThread:#selector(startMethod:) withObject:data waitUntilDone:YES];
});
Could anyone tell me how to salvage this situation, or what I am doing wrong.
That's in the nature of zombie objects. Turning on zombie objects to debug the use of objects after they have been deallocated will obviously turn any such object into a leak. You can't debug using zombies and search for memory leaks at the same time.
I'm assuming that your memory leaks will be happened due to NSData Object being live on memory.
Did you try to save your NSData to documents folder as a file instead of NSData object?
Example
[data writeToFile:filePath atomically:YES];
Docs suggest the following but retain is not allowed when using ARC. What is a workaround, please?
// Create the URL for the source audio file. The URLForResource:withExtension: method is
// new in iOS 4.0.
NSURL *tapSound = [[NSBundle mainBundle] URLForResource: #"tap"
withExtension: #"aif"];
// Store the URL as a CFURLRef instance
self.soundFileURLRef = (CFURLRef) [tapSound retain];
This has driven me nuts for a long time now. I am using Xcode 4.6 but this has been happening for several versions. When I turn on breakpoints and add the Exception Breakpoint, it always pauses on a line of code where I'm setting up an audio player. I set some up before and after the same way, but it only pauses on that one.
Here is the code I'm using:
[[AVAudioSession sharedInstance] setDelegate: self];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: nil];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
self.playedSongs = [NSMutableSet setWithCapacity:9];
[self loadSettingsFromFile];
NSURL *sfxPath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Snap.aiff" ofType:nil]];
self.snapSfx = [[[AVAudioPlayer alloc]initWithContentsOfURL:sfxPath error:nil]autorelease];
self.snapSfx.volume = 1.f;
NSURL *fireworksPath;
if ([OriginalIPadChecker isNotiPadOriginal]) {
fireworksPath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"FireworksSFX.mp3" ofType:nil]];
}
else{
fireworksPath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"NoFireworksSFX.mp3" ofType:nil]];
}
self.fireWorksSfx = [[[AVAudioPlayer alloc]initWithContentsOfURL:fireworksPath error:nil]autorelease];
self.fireWorksSfx.volume = 1.f;
NSURL *poofPath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Remove Poof.mp3" ofType:nil]];
//The line below is the one that it pauses on
self.removePoof = [[[AVAudioPlayer alloc]initWithContentsOfURL:poofPath error:nil]autorelease];
self.removePoof.volume = 1.f;
NSURL *newHighScorePath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"New High Score.mp3" ofType:nil]];
self.theNewHighScore = [[[AVAudioPlayer alloc]initWithContentsOfURL:newHighScorePath error:nil]autorelease];
self.theNewHighScore.volume = 1.f;
NSURL *badgeInTrophyPath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Badge In Trophy.aiff" ofType:nil]];
self.badgeInTrophy = [[[AVAudioPlayer alloc]initWithContentsOfURL:badgeInTrophyPath error:nil]autorelease];
self.badgeInTrophy.volume = 1.f;
NSURL *dingPath = [NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:#"Ding.aif" ofType:nil]];
self.ding = [[[AVAudioPlayer alloc]initWithContentsOfURL:dingPath error:nil]autorelease];
self.ding.volume = 1.f;
The app doesn't crash and the sound plays fine, but the debugger always pauses on that one line—even if I move it somewhere else, it still pauses. I can continue the execution and it works just fine, but this really bugs me.
I don't get why it pauses. Any ideas?
As explained in the comment of Xcode stops on prepareToPlay, the reason for the breakpoint is that you were setting a generic breakpoint of type 'exception on All' which responds to a signal which is fired by the c++ library. It is better to use an "Objective-c" exception breakpoint, which will protect for such cases.
Try this and update the question on where it stops (if it stops):
AVAudioPlayer *foo;
NSError *error = nil;
assert(poofPath);
foo = [AVAudioPlayer alloc];
foo = [foo initWithContentsOfURL:poofPath error:&error];
assert(foo);
[self setRemovePoof:foo];
[foo release];
If the assert kicks in, that's probably an Apple issue. Unfortunately there are cases of Apple internal frameworks using try/catch, and they will trigger the breakpoint. Its not common but does happen.
If in the end that foo is not nil and the error is also nil, the best you can do is enter a bug report at bugreporter.apple.com (which would be great). Also, did you look at poofPath - is there any chance that the URL returns anything other than pristine audio?
My guess is that Apple tries to open and process the file, its gets an internal exception because there is something "odd" or abnormal about the file. Then the framework does additional work, and manages to read the file. So you get your sound but the exception too. Take some common type of mp3 and put that in your app bundle, and try to open it. See if it (and maybe a few other files) gives the same error. Or create a demo project with the sound and upload it (in the end you may need to submit the demo project to Apple in a bug report). These kinds of things should be bug reported.
EDIT: Unfortunately there are cases of Apple internal frameworks using try/catch, and they will trigger the breakpoint. Then, as mentioned earlier, some later code finally figures out how to decode the file and does.
The original poster has responded in a comment that this particular file was created with Audacity, and has heard that such files often have decode issues.
#property ( nonatomic, strong ) NSURL * urlPath;
self.urlPath = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"bark" ofType:#"caf"]];
Running ARC, deployment target 4.3. Instruments gives a leak on the self.urlPath = line.
The self.urlPath is used later on after the view has appeared to setup the AVSoundPlayer. There is NO leak indicated now on the soundplayer, only on this NSURL line. The audio plays, but when the view is pop'd a memory leak occurs.
Any ideas as I've been at this > 12hrs now...
Seems to be a memory leak in Core Foundation only in iOS 6.
Therefore filed as a bug:
Bug ID# 12699818.
Your player is leaking, and if your player leaks, every player will keep their URL and string object too.
self.player = [[[AVAudioPlayer alloc] initWithContentsOfURL:pingURL error:nil] autorelease];
If you declared player as a retaining property, then
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:pingURL error:nil];
will leave the reference count at 2.
self.player = nil;
will make it 1.