iPhone Memory Management - iphone

I'm working on an app and I'd like to make sure that I'm managing memory properly and releasing everything that I should. In my viewDidLoad method I allocate some variables in determining which background to apply to the view (for internationalization) and the app works fine if I don't release them.
The problem is that if I release the variables the app will crash. Code from viewDidLoad is below:
// Set the background image based on the phone's preferred language
NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *backgroundImageName = [[NSString alloc] init];
backgroundImageName = [NSString stringWithFormat:#"background-%#.png",language];
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:backgroundImageName]];
... do some more initialization stuff ...
// IF THE FOLLOWING ARE RELEASED THE APP WILL CRASH!!!
//[backgroundImageName release];
//[language release];
Why would releasing the backgroundImageName and language variables cause the app to crash?

NSString *language = [[NSLocale preferredLanguages] objectAtIndex:0];
Here, language does not need to be released because objectAtIndex: autoreleases it for you. By convention, you own an object if you've alloced, newed, or copyed it, otherwise you don't.
self.view.backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:backgroundImageName]];
Here, the UIColor object does need to be released (because you alloced it).
NSString *backgroundImageName = [[NSString alloc] init];
backgroundImageName = [NSString stringWithFormat:#"background-%#.png",language];
Here the string returned by [[NSString alloc] init] does need to be released (because you've alloced it). However, the next line changes backgroundImageName to point to that a new autoreleased string, losing the last reference to the original string without releasing it (a memory leak). backgroundImageName should not be released because it is already autoreleased.
You can avoid the leaks by releasing the UIColor and eliminating the unused string. For example:
NSString *backgroundImageName = [NSString stringWithFormat:#"background-%#.png",language];
... and ...
UIColor* backgroundColor = [[UIColor alloc] initWithPatternImage:[UIImage imageNamed:backgroundImageName]];
self.view.backgroundColor = backgroundColor;
[backgroundColor release];

short answer :
when you create an object using constructors that dont have the word init then you are not responsible for releasing it
see this for more explanation
also the memory management guide is an excellent resource to know more about memory management in objective c

You're not creating the language string; you're just getting back a reference. Only methods that have "new", "copy", or "alloc" in them (by convention) return non-autoreleased objects. For all other methods, it's assumed that you'll discard the variable, so if you want to keep it around, you MUST retain it. The flip side of this is: you should not release these returned objects unless YOU retained them.
The other problem in this code is that backgroundImageName is being assigned twice. The first initialization is being lost. Get rid of it, and just keep the second one, and get rid of both -release calls, they're not needed.

Related

MutableCopy AllocLeak MemoryLeak

I have an NSTimer that fires once per second.
And every second I have an NSString that needs to be changed.
I've never tried to deal with memory management before so I'm not sure if what I'm doing is right but instruments is saying under "alloc" that the line of code with stringByReplacingOccurrencesOfString has 45MB of "Live Bytes" after about a minute...
(and the live byte count keeps on rising with every second and eventually crashes the app).
I think my issue lies somewhere with the MutableCopy code?
Here is my code:
-(void)myTimer {
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
testedit = [[NSString alloc] initWithFormat:#"example"];
withString1a = [[NSString alloc] initWithFormat:#"e"];//this string gets its values randomly from an array in my real code
forString1a = [[NSString alloc] initWithFormat:#"flk34j"];//this string gets its values randomly from an array in my real code
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];//memory leak /:
}
You are allocating memory for each object twice. When you alloc the second time and assign it to the same variable, the first piece of alloc'd memory becomes inaccessible and unreleasable.
Then you make a mutableCopy of testedit and assign the copy to the original's variable. Again, you leave a piece of inaccessible memory floating around.
The rule with non-ARC memory management is - for every alloc, new, copy or retain you need to have a corresponding release. You have 6 allocs, one copy, and only 3 releases.
Here are some suggestions.
Remove these duplicated allocations:
testedit = [[NSString alloc] init];
withString1a = [[NSString alloc] init];
forString1a = [[NSString alloc] init];
Presumably testedit, withString1a and forString1a are all iVars. (Please declare your iVars as autosynthesized properties and refer to them as self.testedit ... etc. that will make your code so much clearer to stack overflowers).
Take out all of this:
if (testedit) {
[testedit release];
[withString1a release];
[forString1a release];
}
Assuming these are all iVars, the correct place to release them is in your object's dealloc method
In fact withString1a and forString1a can be local variables, as you get their content from elsewhere:
NSString* withString1a = [[[NSString alloc] initWithFormat:#"e"] autorelease];
NSString* forString1a = [[[NSString alloc] initWithFormat:#"flk34j"] autorelease];
You can autorelease them as you don't need them to hang around after the method has finished.
These lines can also be written:
NSString* withString1a = [NSString stringWithFormat:#"e"];
NSString* forString1a = [NSString stringWithFormat:#"flk34j"];
(-stringWithFormat is a convenience method that returns an autoreleased object)
That leaves us with these two lines.
testedit = [[NSString alloc] initWithFormat:#"example"];
testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] mutableCopy];
It's not clear why you are treating testedit as an immutable string in the first line and a mutable string in the second. You don't need a mutable string here at all, as you are replacing testedit with a new string.
self.testedit = [[NSString alloc] initWithFormat:#"example"];
self.testedit = [[testedit stringByReplacingOccurrencesOfString:withString1a
withString:forString1a] copy];
(you need copy as stringByReplacingOccurrencesOfString:withString: returns an autoreleased object, and here you want to keep hold of it)
THE last piece of the jigsaw is getting rid of your _testedit iVar memory allocation. You do this in the dealloc method of your object:
- (void) dealloc {
[_testEdit release];
[super dealloc];
}
(Note that init, accessor, and dealloc methods are the three places where you should not refer to an iVar using property syntax.)
All good, but really, you should be using ARC! You are _far_more likely to introduce memory bugs this way than if you rely on the compiler to manage memory for you.
I would suggest you to make use of #property here.
In .h file declare the properties as:
#property (nonatomic, retain) NSString *testedit;
#property (nonatomic, retain) NSString *withString1a;
#property (nonatomic, retain) NSString *forString1a; //if required write the #synthesize as well in .m class
You can write your timer method as:
-(void)myTimer {
self.testedit = #"example";
self.withString1a = #"e";//this string gets its values randomly from an array in my real code
self.forString1a = #"flk34j";//this string gets its values randomly from an array in my real code
self.testedit = [self.testedit stringByReplacingOccurrencesOfString:self.withString1a withString:self.forString1a];
}
In dealloc method, you can set all the above properties as nil (self.testedit = nil;) or do a release on them([testedit release];).
If possible, try to switch to ARC, you dont have to worry about the memory management. The problem with your code was that you are using a lot of alloc/init statements without releasing the variable before doing it. This causes it to lose the reference of that variable and you will leak it. You dont need that many allocation statements. For every allocation or retain, there should be a corresponding release/auto-release statement.
If you're using ARC you shouldn't have an issue. If you aren't using ARC you can try adding autorelease:
testedit = [[[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy] autorelease];
You are getting a memory leak because you never de-allocate testedit. Whenever you call alloc, that means you need to deallocate it. This usually just means calling release.
Do something like this instead, then be sure to free up the memory you've allocated:
NSString* newString = [[testedit stringByReplacingOccurrencesOfString:withString1a withString:forString1a] mutableCopy];

Dealloc objects of another class

Hi I generally create objects of another classes. can you please tel me if this wil be in the auto release pool? or should we release it manually.
if you init copy or new them you'll have to deallocate them if you put an autorlease with the allocation then they will be autoreleased
for example
Foo *foo = [[Foo alloc] init]; //you'll have release it somewhere yourself
And
Foo *foo = [[[Foo alloc] init] autorelease];// this will be autreleased
The simple case is : if you use init, you are responsible for releasing it, either by calling release or by calling autorelease.
e.g.
NSString *myString = [NSString alloc] init]; // You need to release this
...
[myString release]; // Now it's released - don't use it again!
or if you are going give it to someone else
NSString *myString = [NSString alloc] init]; // This needs releasing
...
return [myString autorelease]; // You are finished with it but someone else might want it
However, there's a few other cases.
NSString *myString = [NSString stringWithFormat:#"hi"];
This object is in the autorelease pool already - don't release it!
NSString *secondString = [myString copy];
This object needs releasing - it is not autoreleased.
Rule of thumb : Anything with init, copy or new in the name - you made it, you release it. Anything else will be autoreleased.

NSArray Memory Management

For some reason when I release the NSArray I get the EXC_BAD_ACCESS exception. Here is the implementation:
-(void) loadAllAlphabets
{
NSBundle *bundle = [NSBundle mainBundle];
NSArray *imagesPath = [[NSArray alloc] init];
imagesPath = [bundle pathsForResourcesOfType:#"png" inDirectory:#"Images"];
alphabets = [[NSMutableArray alloc] init];
NSString *fileName = [[NSString alloc] init];
for(int i=0; i<= imagesPath.count -1 ; i++)
{
fileName = [[imagesPath objectAtIndex:i] lastPathComponent];
CCSprite *sprite = [CCSprite spriteWithFile:fileName];
sprite.userData = [[fileName stringByDeletingPathExtension] uppercaseString];
[alphabets addObject:sprite];
}
// release fileName
[fileName release];
fileName = nil;
[imagesPath release]; // this causes the application to crash with EXC_BAD_ACCESS
// imagesPath = nil;
}
UPDATE 1:
So, the problem was that although I was responsible for releasing the imagesPath object since I used alloc that soon become irrelevant when pathsForResourcesOfType returned an autorelease object.
This means I should not release the imagesPath object manually.
The following line should be used:
NSArray *imagesPath = [bundle pathsForResourcesOfType:#"png" inDirectory:#"Images"];
UPDATE 2:
Another question which is related to this post. In the following code I initialize a new NSMutableArray manually.
alphabets = [[NSMutableArray alloc] init];
Later I insert CCSprite (Cocos2d objects) into alphabets array. CCSprite are autorelease objects. Do I still have to release alphabets manually? Since, after some time all objects are released and memory will be returned but then what will be left inside alphabets NSMutable array?
I think the confusion is here:
NSArray *imagesPath = [[NSArray alloc] init];
imagesPath = [bundle pathsForResourcesOfType:#"png" inDirectory:#"Images"];
The first line creates a new object. This object really needs to be released.
The second line over-writes that object with a new, self-managed object. This does not need to be manually release.
This means that you're leaking the first imagesPath.
In general, you need to release an object if you alloc or copy it. And you shouldn't over-write an object before you release (or autorelease) its content.
general rule of thumb in memory management - you should release an object only if you obtain it using method that contains new, copy or alloc in it (standard method follow that rule and you should stick to it as well).
In your case you obtain imagesPath object using pathsForResourcesOfType: method which returns an autoreleased object so you must not release it yourself.
Edit: yes, you need to release alphabets object somewhere (for the same reason - you got it with alloc method).
Objective-c containers take an ownership of objects added to them, that us when objects are added to an array they get retained so it is guaranteed that their life time is at least as long as the life time of container. When you remove object from collection or collection itself is destroyed then its members get released (to compensate retain on add).
Also, you are leaking memory as you initialize imagesPath with an empty non-mutable array and then discard it when you assign he result of pathsForResources: to it. Just do this instead:
NSArray *imagesPath = [bundle pathsForResourcesOfType:#"png" inDirectory:#"Images"];
Same error with fileName. Not need to initialize it with an empty non mutable string.
And also do not release fileName since it is also an autoreleased object.

Why Instruments report a leak?

I am developing an iphone app. Instruments reported a leaked object ServiceTypes. Below is the relevant code. Does anyone have any ideas? Thanks a lot for your help.
ServiceTypes *serviceTypes = [[ServiceTypes alloc] init];
if ([userConnection getServiceTypes:serviceTypes]) {
if ([serviceTypes.types length] > 0) {
NSArray *array = [[NSArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString: SERVICE_TYPE_DELIMITOR]];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:array];
[array release];
}
}
[[self typesTableView] reloadData];
[serviceTypes release];
It doesn't look like serviceTypes is being leaked. From the code you posted, serviceTypes is always released at the end of the method, and it doesn't appear to be retained anywhere in your sample. My question is: what happens inside getServiceTypes:. Does that method retain the serviceTypes parameter?
One more thing. If serviceRequestTypes is an instance variable (and it looks like it is), then you may be leaking memory by reassigning it without releasing the existing serviceRequestTypes object first. You should either rewrite serviceRequestTypes to be a property and use a synthesized accessor or make sure to release it every time before assigning. If its current value is nil, no big deal; the release message will simply be ignored. For example:
[serviceRequestTypes release];
serviceRequestTypes = [[NSMutableArray alloc] initWithArray:[serviceTypes.types componentsSeparatedByString:SERVICE_TYPE_DELIMITER]];

What's the point of this in objective-c

SomeObject *temp = [[SomeObject alloc] init]
self.theObject = temp;
[temp release];
Why is it always done that way? Why not
self.theObject = [[SomeObject alloc] init];
If the theObject property is a retaining property, the first way is correct, because it doesn't leak memory. It's also more efficient than the correct way to write the second version, which is this:
self.theObject = [[[SomeObject alloc] init] autorelease];
Whenever you create an object with alloc you're in charge of releasing it somehow, whether by release or autorelease.
The second version leaks the SomeObject instance, since self.theObject will call a setter that, if properly written, retains the object.
You could just do
theObject = [[SomeObject alloc] init];
and some people certainly do. Others prefer to always use accessors though, either for consistence or to avoid bugs if the accessors have side effects (for exmaple, you would be bypassing KVO notification, which could be a problem if it's not part of an init method).