Objective-C Memory Management

Wednesday, July 8, 2009 by darco
Posted in , ,

A while back a friend of mine mentioned that for programmers starting to learn Objective-C often have difficulty fully understanding how Objective-C handles memory management. Objective-C memory management isn't really all that difficult once you get the gist of it, but it can be confusing at first.

This short article covers the basics of the normal reference-counted Objective-C runtime. Garbage collection can wait for another day.

Basics

In Objective-C, object allocation and initialization are two distinct steps. For example:

[[NSMutableString alloc] init]

This will allocate and initialize an NSMutableString object, and it will have a retain count of 1. You can then retain and release it to your hearts content and it will behave as you would expect—when you perform the release that causes the retain count to hit zero, a dealloc message is automatically sent to the object and it goes away.

Tip: If a message has alloc, create, or copy in its name, then it will return an object which it is your responsibility to release. This is called the create rule.

A special exception to the retain/release semantics are constant strings:

@"Hello!"

Constant strings act just like NSString objects, but you do not have to release them. You can retain and release them if you want, but these constant objects ignore these messages.

Autorelease Pools

Autorelease pools are a way to dramatically lower the bookkeeping overhead of dealing with retain/release semantics. When you send the message autorelease to an object, it gets added to a list in the most recently allocated NSAutoreleasePool on that thread. Once that pool is itself released (or drained), it will send a real release message to all of the objects that were added to that autorelease pool. In practice this allows you to behave as if the environment was garbage-collected—For the most part you don't have to worry about explicitly releasing objects as long as they are added to the autorelease pool. In most cases you don't have to even worry about creating an autorelease pool itself because one is almost always already in place, created by the runloop.

More Shortcuts

Now, remember when I said that object allocation and initialization are two distinct steps? While that is true, there are shortcuts. There are convenience constructors in practically every object which allocate, initialize, AND autorelease the object in one step. For example, the following two expressions are equivalent:

[[[NSMutableString alloc] init] autorelease]

[NSMutableString string]

This applies to just about every object, and is (usually) just a syntactic simplification so that the engineers don't go crazy with square brackets. In cases where you don't mind releasing an object manually (or explicitly don't want it added to an autorelease pool), you simply create the object using the alloc/init method and then release it when you are done.

The name of this convenience constructor is usually the last capitalized word in the class that you are constructing. EX:

[NSMutableArray array]
[NSMutableDictionary dictionary]

Some of these constructors can take arguments, and are analogous in function to their init counterparts:

[NSMutableString stringWithUTF8String:"UTF-8 is great!"]

Note: Collections (NSDictionary, NSArray, NSSet, etc) retain the objects inside of them. The retain count is not affected by reading an object from a collection.