Owning Up - Release, Retain, and Object Ownership
by Rob BajorekOriginally posted: July 21, 2009
Ever used the NSString class? If you’re reading this, you probably have. Let’s look at a couple of ways to create NSStrings with the …WithFormat: methods.
- (id)initWithFormat:(NSString *)format …
Returns an NSString object initialized by using a given format string as a template into which the remaining argument values are substituted.
+ (id)stringWithFormat:(NSString *)format, …
Returns a string created by using a given format string as a template into which the remaining argument values are substituted.
Hmm, they both sound about the same, take the same arguments, and return an NSString object. Apple made these two functions for a reason, so what’s the difference?
There are semantic differences in usage, but the real difference I’m talking about is who owns the NSString object.
Object Ownership in Objective-C
From the object’s perspective, what does it mean to be owned? According to Apple’s Memory Management Guide, an object exists as long as it has at least one owner. There are no restrictions on how many owners an object has; it can have none or a hundred. An owner relinquishes ownership by sending their object a release or autorelease message. When the last owner has given up ownership, the application will dispose of the object automatically.How do you know if an object is yours?
• If you create an object with alloc, new, or copy, it’s yours.
• If you retain an object, it’s yours.
• Everything else is not yours.
That’s it.
What does that mean? The main point of object ownership is you choose to own an object because you don’t want it deallocated. If an object is not yours and you want to keep it around, you must retain it and make it yours. Otherwise, the system may take it away from you.
We’re also talking about memory management. You must clean up after yourself. If an object is yours and you’re done with it, you must release or autorelease it. If you don’t, you create a leak: allocated memory that cannot be freed because you’ve lost the reference to it. Leaks cause memory problems, and if this is an iPhone app then Apple may reject it until you fix the mess.
An example
Here’s a snippet that demonstrates different ownership situations./* Create some strings */
int count = 1;
NSString *string1 = [[NSString alloc] initWithFormat:@"This is string %d. It's mine, so I need to release it when I'm done.", count];
count++;
NSString *string2 = [NSString stringWithFormat:@"This is string %d. It is not mine, so I won't release it.", count];
count++;
NSString *string3 = [[NSString stringWithFormat:@"This is string %d. We are retaining it, so we must release it later.", count] retain];
count++;
... // code using the strings snipped
/* Done with the strings, get rid of them */
[string1 release]; // Released and gone
// [string2 release]; // string2 is not ours, so releasing it is an error
[string3 autorelease]; // Still here until NSAutoReleasePool is drained
The string1 object is created with alloc and initialized by initWithFormat:. Checking the rules, alloc is one of our special keywords, so string1 is ours. We need to release it, and in fact we do so. No problem.
Our string2 object is created with the NSString factory method stringWithFormat:. The method name doesn’t use the ownership keywords, so string2 is not ours. It will be autoreleased. In fact, if you release it…
Program received signal: “EXC_BAD_ACCESS”.
Oops! Don’t do that!
Lastly, string3 is an autoreleased string like string2, but this time we retained it. Using retain takes ownership of it, so string3 is ours. We need to release it when we’re finished with it. This time though, we chose to autorelease it. We don’t own it anymore, but it’s still around.
Release vs. Autorelease
As we’ve seen, there are two ways to disown an object: release and autorelease. What’s the difference?If you use release, the effect is immediate. If you were the last owner, that object is gone and memory is freed.
CSWidget *widget = [[CSWidget alloc] init]; // New widget, owned by me
[widget shake];
[widget twirl];
[widget release]; // widget is gone
Usually this is fine, but that may not be what you want.
Take “(NSString *)stringWithFormat: (NSString *)format, …” . How can stringWithFormat: disown its returned object without losing it? By using autorelease.
+ (CSWidget *) widget {
CSWidget *widget = [[CSWidget alloc] init]; // New widget, owned by me
[widget autorelease]; // Not owned by me anymore, but still exists
return widget;
}
We created a widget object and disowned it, but its release is delayed until the current NSAutoReleasePool is drained. That is a subject for another post, but simply, the pool is drained after every pass of the main event loop.
Short version: release = immediate, autorelease = delayed.
For the Mac folks
On Mac you can use garbage collection now, so should you put in retain and release messages if they are just no-ops? Generally no, but with one exception. If there’s a chance you’ll port your Mac code to iPhone, I would consider using reference-count rules. If you don’t, you’ll have to go through the code again and fix it up to work on iPhone.More information
I recommend reading the Memory Management Programming Guide for Cocoa for a complete explanation of object ownership and memory management.Review
• Know the ownership keywords (alloc, new, copy, retain)
• Retain objects you want to keep
• Don’t release objects that aren’t yours
• Use release when you don’t care if an object is deallocated immediately
• Use autorelease to give up ownership but delay an object’s release
Good luck!