Memory Management in Objective-C
Pages: 1, 2, 3
autorelease
Another way we can decrease an object's reference count is by sending it an autorelease message. When you send an autorelease message, the receiver is not immediately freed from memory, as is the case with release. Rather, autorelease decreases the receiver's reference count by one at some point in the future. autorelease thus provides added flexibility when releasing an object and lets us use it a little bit longer before it is actually de-allocated.
autorelease works by making use of an object known as an "autorelease pool." Whenever you send an object an autorelease message, it is added to the autorelease pool. At the end of the event loop, this autorelease pool is released by the application object and then all of the objects contained within it are released. At the beginning of the next loop, a new pool is created and the process is repeated ad infinitum. For practical purposes, an autoreleased object is considered to be valid anywhere within the scope where it received the autorelease message.
For example, our button method from MemApp can be changed to incorporate autorelease, rather than release.
- (IBAction)goButton(id)sender
{
AClass *ourObject;
ourObject = [AClass alloc];
[ourObject autorelease];
// We can still use ourObject until
// the very end of this method!
}
When we run this code through ObjectAlloc, we find that the instance counts are exactly the same as we got before with release. This shouldn't surprise you because the object is released after the end of the method.
autorelease is especially useful when we have a method that creates and returns an object. In this situation, if we follow the rules, we have to make sure any object we create is destroyed before it's too late. Using release in this case won't work because the object we're trying to return will be destroyed before it can be returned.
- (NSString)releasedString
{
NSString *string = [[NSString alloc] initWithString:@"The Sender of this message will never see this string…"];
[string release]; // we have to do this or we'll get a memory leak
return string; // but what are we returning?
}
The solution to this is to use autorelease which allows us to properly deal with objects that we create and own, while giving the sender of the message a chance to grab onto the returned object for its own use.
- (NSString)autoreleasedString
{
NSString *string = [[NSString alloc] initWithString:@"The Sender of this message will never see this string…"];
[string autorelease]; // we have to do this or we'll get a memory leak
return string;
}
We can now return a string to the message sender and let our minds rest comfortably knowing that we've fulfilled our duty to prevent memory leaks. These last few examples provide a perfect place to jump into our next topic -- convenience constructors -- which fit into the mold of a method that creates and returns an autoreleased object.
Convenience constructors
By now you have probably noticed in the class documentation that most Cocoa classes have a set of class methods that are named in the format +className.... These special class methods are called "convenience constructors," and are used to create temporary objects. What I mean by temporary is that objects returned by a convenience constructor are assumed to be autoreleased, and are thus valid only within the method that uses the convenience constructor.
An example of one of the many convenience constructors available is the NSString method, +stringWithCString:. We can use this method instead of creating an NSString instance using the usual alloc/init process. For example, consider the following code that uses alloc and init:
NSString *string = [[NSString alloc] initWithCString:"Hello"];
[textField setStringValue:string];
[string release];
This can be shortened using a convenience constructor:
NSString *string = [NSString stringWithCString:"Hello"];
[textField setStringValue:string];
// don't need to release string since objects
// returned by convenience constructors are
// assumed to be autoreleased.
Convenience constructors also make it less cumbersome to nest messages:
[textField setStringValue:[NSString stringWithCString:"Hello]];
So, if you need a string (or any other object) to exist only within a method, it's often easier, cleaner, and more readable to use a convenience constructor.
If you want to set an instance variable using a convenience constructor, you have to send it a retain message so that it is not released when the autorelease pool is cleared out, like so:
// assume stringInstanceVariable exists
stringInstanceVariable = [[NSString stringWithCString:"Hello"] retain];
retain is a way to assess object ownership on objects that you didn't initially create, so this extends our rule of matching every alloc with a release or autorelease, and now we also have to match any retain messages with release or autorelease.
Find out more about memory management
In this column I have tried to cover the basics of memory management in Cocoa and Objective-C. There are several other excellent articles and references available that I strongly encourage you to read. These articles go into more detail, provide additional code examples, and cover various "traps" that you have to look out for. Below is a list of these references:
Very Simple Rules for Memory Management in Cocoa by mmalcolm crawford provides a good summary of what we have discussed here, including several examples that show how to avoid memory leaks in your code.
Hold Me, Use Me, Free Me by Don Yacktman is a detailed overview of the problem of memory management and how it is handled in Cocoa and Objective-C.
Object-Oriented Programming and The Objective-C Language, Chapter 6, "Object Ownership and Automatic Disposal" from Apple. Anyone serious about learning Cocoa should read this book. Editions of this book published after December 2000 contain the chapter about memory management. This book covers many of the same things we talk about here, but comes straight from the developers at Apple. It also emphasizes the idea of object ownership. You can never have too many references!
Class references for NSObject and NSAutoreleasePool can be found on the Apple web site. The methods
+alloc,-release,-retain, and-autoreleaseare all defined and described here. TheNSAutoreleasePoolreference goes into more detail regarding the operation of autorelease pools, and includes a description about how you can create your own autorelease pools, and when you might want to do so.
Well, that's it for now for memory management. I hope I have given you a good feeling for how reference counting and memory management works in Objective-C and Cocoa. If you're still a bit shaky, don't worry too much. In the next several columns we will be building an application where we will follow the rules of good memory management, so you will be able to see how we implement all of this in real code. In the next article, we will build the interface for this application and learn a few things about tables in interfaces and the NSTableView class.
Michael Beam is a software engineer in the energy industry specializing in seismic application development on Linux with C++ and Qt. He lives in Houston, Texas with his wife and son.
Read more Programming With Cocoa columns.
Return to the Mac DevCenter.

