I\'m slowly teaching myself cocoa for the iPhone(through the Stanford Class on iTunes U) and I\'ve just gone through the part on memory management, and I wanted to hopefully
Last part first: You will indeed have to auto/release Me
. However, you will also have to add [firstName release];
and [lastName release];
in -dealloc
; or better yet; self.firstName = nil;
As for string literals; this part gets a bit hairy, but [@"String literal" release]
is essentially a noop. As such, there is a difference between the two temp objects, but as you won't generally know which one you'll be dealing with, adding [temp release]; is generally the safe choice, unless you know it'll contain an autoreleased object.
The rule is simple: if you alloc
, copy
or retain
, it's your responsibility to release
. If you didn't, it's not. However, if you need to rely on an object staying around, you have to retain
(and subsequently release
).
We can treat the string literal according to the rules - you don't need to release
it because you don't own it. That's simple; there's no need to worry about whether they're special cases or not, just follow the rules and you'll be fine.
I wrote up a blog post with a collection of articles about the Cocoa memory management rules; I'd recommend following up some of the references.
NSStrings created with the @"String here"
syntax are constant strings. These are different from normal strings. Much like normal C constant strings, they are created when your program loads and exist for its entire lifetime. The NXConstantString class, to which they belong, ignores all memory management messages. You can retain
and release
them all you like and it won't make any difference.
For a string created with an [[NSString alloc] initWith...]
-type method, normal memory management rules apply. I'd strongly recommend reading the linked docs — they're not complicated, and after reading them, you will know pretty much everything you will ever need to know about Cocoa memory management.
About firstName/lastName.
You should always, for clarity, remember to specify the properties' attributes. The setter default attribute is assign, in this case you want to use retain.
@interface Person : NSObject
{
NSString *firstName;
}
@property (retain) NSString *firstName;
@end
With retain each and only time you use the dot notation to assign a value the compiler inserts a retain: just remember to always use it. For consistency I advice you to write your initializer this way:
- (id) initWithFirstName:(NSString*) aString
{
self.firstName = aString;
}
and the dealloc method this way:
- (void) dealloc
{
self.firstName = nil;
}
About @""-type objects. They are constant NSStrings objects. Just use them as the were (they are) NSString objects and never release them. The compiler takes care of them.
Does the NSString class call autorelease automatically as part of the assignment?
The NSString class didn't do anything because you didn't send it a message. All you did was assign to a variable. NSString doesn't find out about this, and it's none of its business.
Also, is there any difference between the two *temp objects here after these statements? They both contain the same string, but are there memory/usage ways where they differ?
They're both NSStrings, they both contain the same value, and they're both presumed immutable. That's all you should ever care about.
Secondly, with properties, I'm assuming that the autorelease is handled automatically. If I have this:
@property NSString *firstName; @property NSString *lastName; - (void) dealloc { //HERE!!!! [super dealloc]; }
I'm assuming I don't need to add
[firstName release]
and[lastName release]
(at//HERE!!!!
), since that's automatically handled by the properties. Is that correct?
No. NSObject will not release all your property values for you; you still need to release them yourself there.
Also, don't do self.firstName = nil
and self.lastName = nil
in dealloc
. Those translate into messages (to your accessor methods), and when you do that in dealloc
, you're sending messages to a half-dealloc
ked object. That's asking for trouble. The same applies the other way to initializing property values in init
: Using your properties/accessors there would be sending messages to a half-init
ed object.
NSString *foo = @"x";
. Logically, if you had to release
the result of that, it you would have to release
the parameter to initWithString
, and both the parameters to initWithFirstName:lastName:
, too.release
or autorelease
firstName
and lastName
. I've seen warnings about not using property syntax in destructors, which I think is the same reason you don't use virtual functions in C++ constructors and destructors.Your assumption was wrong. You must do either this:
Person *Me = [[Person alloc] initWithFirstName: @"Drew"
lastName: @"McGhie"];
...
[Me release];
or this:
Person *Me = [Person personWithFirstName: @"Drew"
lastName: @"McGhie"];
...and make sure your Person object handles +personWithFirstName:lastName:
correctly, i.e. [[[self alloc] initWithFirstName: firstName lastName: lastName] autorelease]
.
You should probably do the one with less code. Clarity is important, NSAutoreleasePool
will probably never be your bottleneck, and if it ever is it's easily fixed.
I think people put a lot of effort into avoiding the class messages that return an autorelease
'd object that just isn't merited. It's premature optimization, in that it probably isn't necessary and may not even be the correct thing to do. And it's harder to maintain, you'll very likely be chasing leaks forever.
Also, you're going to autorelease
an object you had to init
(i.e. alloc
+ initPersonWithFirstName:lastName:
instead of using a class message like personWithFirstName:lastName:
), I'd suggest you do it immediately. Otherwise, you're potentially chasing that same kind of leak. So if you're not going to add a personWithFirstName:lastName:
method to Person
, do this instead:
Person *Me = [[[Person alloc] initWithFirstName: @"Drew"
lastName: @"McGhie"] autorelease];
Summary: Cocoa does a lot to help you with memory management. Make sure you don't fight it.
Updated based on Jon's feedback in comment.