Memory Leaks - Objective-C - iphone

Can anyone see potential leaks in this code? I'm getting a "100%" leak according to Instruments on the line "NSString *ender = [temp stringFromDate:now];"
NSDateFormatter* temp = [[NSDateFormatter alloc] init];
[temp setDateFormat:#"yyyy-MM-dd"];
NSDate *now = [NSDate date];
NSString *ender = [temp stringFromDate:now];
DashboardViewController *controller = [[DashboardViewController alloc] init];
[controller initWithStartDate:ender andEndDate:ender];
[controller initAccount:account];
[self presentModalViewController:controller animated:NO];
[temp release];

Do you release controller after all that stuff?

This advice is unrelated to original question, but I think you should rename the initWithStartDate:andEndDate: and initAccount: methods since typically methods with "init" in the name return new instances.
Perhaps create your own -(id)initWithStartDate:endDate:account: and call the designated initializer from within.
Then you would create a new controller instance with
DashboardViewController *controller = [[DashboardViewController alloc] initWithStartDate:ender endDate:ender account:account];
Gonzalo

Since you pass your controller instance to the -presentModalViewController: method, that method will retain your controller. So you can safely release your controller, but you also should release your controller, since the memory management rules state that objects that you alloc+inited are owned by you and must be released.
On the other hand - just a small note - NSDateFormatter is a "heavy" object, cache the instance and reuse it, if it's possible. Probably this is also the reason why Apple deprecated this method. You might call -init on NSDateFormatter from iOS 2.0 till iOS 3.2, but it is deprecated after iOS 3.2 .

Related

Understanding memory management in Objective-C

I've got the following code that works OK, but I'm not sure if I understood correctly some memory management concepts:
#import "mapPoint.h"
#implementation mapPoint
#synthesize coordinate, title, subtitle;
-(id)initWithCoordinate:(CLLocationCoordinate2D)c title:(NSString *)t {
[super init];
coordinate = c;
[self setTitle:t];
// Set date as subtitle
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle:NSDateFormatterMediumStyle];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
NSString *myDate = [dateFormatter stringFromDate:[NSDate date]];
[self setSubtitle:myDate];
[dateFormatter release];
// Look for city and state; when found, set it in subtitle, replacing date
geocoder = [[MKReverseGeocoder alloc] initWithCoordinate:c];
[geocoder setDelegate:self];
[geocoder start];
return self;
}
-(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error {
NSLog(#"%#", error);
}
-(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark {
[self setSubtitle:[NSString stringWithFormat:#"City: %#, State: %#", [placemark locality], [placemark administrativeArea]]];
}
-(void)dealloc {
[title release];
[subtitle release];
[geocoder release];
[super dealloc];
}
#end
As I created the geocoder object via the alloc method, I have to release it (done in dealloc). Correct?
In method reverseGeocoder:didFindPlacemark a NSString is created with the convenience method stringWithFormat. As I didn't use alloc, I'm not responsible for releasing that (I assume that method uses autorelease). Is that right?
The object placemark returns two NSStrings, locality and administrativeArea. Again, I didn't create those strings, so I'm not releasing them. However, given that they are part of the subtitle property of my mapPoint object, I don't want those strings to disappear, but they probably were created with autorelease. The property subtitle is declared with retain. Is is correct to assume that it will retain the NSString created with the convenience method, preventing it's premature destruction?
Thanks, and apologies if the questions are complicated... the subject is.
geocoder is an ivar in your class? Then your code is correct. Note that, since the geocoder is useless after it returns a result, you could release it (and set the ivar to nil) in the appropriate delegate methods to allow the memory to be reclaimed earlier.
Correct, mostly. If you had used a method starting with "new" or containing "copy" to get the instance of the object, you would also be responsible for releasing it.
Correct on all points. Note that if you were to implement setSubtitle: yourself instead of allowing #synthesize to do it, you would be responsible for implementing that behavior in your implementation of setSubtitle:.
Edit:
I see in comments that you are particularly concerned about point 3. The strings from [placemark locality] and [placemark administrativeArea] are passed as parameters to NSString's stringWithFormat method, after which they are irrelevant because their content has been copied into the new string that stringWithFormat returns. That is the only string you really have to worry about, and as has been pointed out setSubtitle: will retain that string.
Much has been written and said -- here and elsewhere -- about Cocoa memory management. Fundamentally, it's all an attempt to paraphrase or explain this: Memory Management Rules. Accept no substitutes. :-)
Yes, you need to release geocoder in dealloc
Yes, you are not responsible for releasing the NSString
Yes, you are not responsible for releasing those NSStrings.
To obtain a better understanding of the memory management rules and standards, I would suggest reading the 'Memory Management Programming Guide' In particular, you may want to take some extra time to read the section 'Object Ownership and Disposal'.
Others have already addressed your main questions, but I'd like to point out a few other things:
It is conventional to assign the result of [super init] to self, like this:
- init
{
self = [super init];
if (!self) return nil;
// do initialisation
return self;
}
There are other, similar constructs that revolve around the value returned by [super init], but they always (by convention) involve assigning to self first.
Although unlikely to cause any problems in this case, it is generally more acceptable to avoid using accessor methods like setTitle: and setSubtitle: inside an initialiser method. The reason being that you may inadvertently trigger KVO notifications when your object is only in a partially-initialised state.

ObjectiveC - Releasing objects added as parameters

Ok, here goes.
Being a Java developer I'm still struggling with the memory management in ObjectiveC. I have all the basics covered, but once in a while I encounter a challenge.
What I want to do is something which in Java would look like this:
MyObject myObject = new MyObject(new MyParameterObject());
The constructor of MyObject class takes a parameter of type MyParameterObject which I initiate on-the-fly.
In ObjectiveC I tried to do this using following code:
MyObject *myObject = [[MyObject alloc] init:[[MyParameterObject alloc] init]];
However, running the Build and Analyze tool this gives me a "Potential leak of an object" warning for the MyParameter object which indeed occurs when I test it using Instruments. I do understand why this happens since I am taking ownership of the object with the alloc method and not relinquishing it, I just don't know the correct way of doing it.
I tried using
MyObject *myObject = [[MyObject alloc] init:[[[MyParameterObject alloc] init] autorelease]];
but then the Analyze tool told me that "Object sent -autorelease too many times".
I could solve the issue by modifying the init method of MyParameterObject to say return [self autorelease]; in stead of just return self;. Analyze still warnes about a potential leak, but it doesn't actually occur. However I believe that this approach violates the convention for managing memory in ObjectiveC and I really want to do it the right way.
Thanx in advance.
Ok, here's a suggestion.
MyParameter *param = [[MyParam alloc] init];
MyObject *obj = [[MyObject alloc] initWithParam:param]; // do you know if param is retain'd or not?
[param release];
Why do it this way? This is the pattern used throughout ObjC/Cocoa. You add objects to NSArrays this way:
MyThing *thing = [[MyThing alloc] init];
[myMutableArray addObject: thing]; // this calls [thing retain]
[thing release];
You may also want to try to do this:
MyObject *obj = [[MyObject alloc] initWithParam: [MyParameter parameter]];
where:
+ (id) parameter
{
return [[[self alloc] init] autorelease];
}
that way you don't have to worry about it. This is the same as
[NSData data];
[NSArray array];
I hope that helps. Generally, it isn't a good idea to use init during another method call (like a setter or another init). Hiding it behind a Class Method (+ (id) parameter) means the user knows it'll be autorelease'd.
If you're ever unclear about how many retain's or release's something has, you can always do something like this:
[EDIT]
Caveat: Apparently you should never use -retainCount. I find it useful for teaching learners the basics of retain'd Memory Management, but the point is well taken.
Never Use it in actual code or for performance testing. This is only used to learn what retain does (and I believe it functions properly in this case). It will never give you an intelligent answer for an object which is autorelease'd or further retain'd by a NSArray or Other Foundation/AppKit/UIKit Classes
MyParameter *param = [[MyParam alloc] init];
NSLog(#"param retain count: %d",[param retainCount]); // should be 1
MyObject *obj = [[MyObject alloc] initWithParam:param];
NSLog(#"param retain count: %d",[param retainCount]); // should be 2, if MyObject retains it.
[param release];
NSLog(#"param retain count: %d",[param retainCount]); // should be 1
Also, when you dealloc MyObject, you'll need to release param if you retain'd it during initialization.
The following guide put out by Apple should help you to understand Objective-C Memory Management a little better.
MyThing *thing = [[MyThing alloc] init];
[otherThing methodWithAThing:thing];
[thing release];
or:
[otherThing methodWithAThing:[[[MyThing alloc] init] autorelease]];
or (if there is a "convenience constructor" on the class you're using):
[otherThing methodWithAThing:[MyThing thing]];
MyObject *myObject = [[MyObject alloc] init:[[[MyParameterObject alloc] init] autorelease]];
should be ok, if there is no release in the init (there should definitely not be a release in the init). I often make a class method which makes a autoreleased object. So the code would be:
// using it:
MyObject *myObject = [[MyObject alloc] init:[MyParameterObject defaultParameters];
// in the class implementation of MyParameterObject
+ (MyParameterObject*) defaultParameters{
MyParameterObject* out = [[MyParameterObject alloc] init];
// set some values
return [out autorelease];
}
[[MyObject alloc] init:[[[MyParameterObject alloc] init] autorelease]]
Without knowing what's going on in the init method, this seems fine.
NB, though, that it's more Objective-Cish to spell this "initWithParameterObject:". Though they gag people new to the language, Obj-C's descriptive method names are actually really helpful for code readability.

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).

iPhone Memory Management

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.