by Alex Rozanski

Cocoa Memory Management Etiquette

Jul 20th 2009Published in Cocoa

I often find myself answering questions on Stack Overflow where users question whether they are managing memory correctly. I often refer to Apple’s guide on Object Ownership and Disposal, from the Memory Management Programming Guide for Cocoa, since this explains why what they are doing is either correct or incorrect.

Notably are the object “ownership” conventions which the guide outlines. Ownership over objects determines whether or not it is your responsibility to manage an object’s memory or not. Following this memory management etiquette allows your applications to work in conjunction with other objects and libraries and ensure they follow the accepted memory management procedures; they cover three main points about memory management for objects:

1. Object Creation and Ownership

You own any object you create.
You “create” an object using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy).

This is an important point for managing memory for objects in Cocoa; there is some ambiguity when using methods that return objects on whether you have to manage the memory for those returned objects, or whether this is done for you.

For example, take the NSString class. Several string creation methods exist, which seem to have counterparts, for example initWithCharacters:length: and stringWithCharacters:length:. But what’s the difference? Taking a look at the method declarations in more detail, you will see that initWithCharacters:length: has the method declaration:

- (id)initWithCharacters: (const unichar *)characters length: (NSUInteger)length;

As with all Objective-C methods, the minus sign denotes that the method is an instance method, and in this way you must instantiate an NSString object to call initWithCharacters:length: upon. How do you do this? By first calling alloc on NSString, which is a “method whose name begins with “alloc” or “new” or contains “copy””. As of this, if you create an NSString object using the initWithCharacters:length: method, you must memory manage that object yourself, since you take ownership of that object by creating it.

The method declaration of stringWithCharacters:length: is as so:

+ (id)stringWithCharacters: (const unichar *)chars length: (NSUInteger)length;

The plus sign denotes a class method of NSString this time, and so when calling this method, you do not need to first instantiate an NSString object, instead calling it on NSString directly. In this way, it tells you that you do not need to memory manage the NSString returned, and this will be done for you (since the NSString is returned, it will be autoreleased).

Naming conventions

Naming conventions for creation methods in the Cocoa classes often follow patterns; methods that start with “init” are often custom implementations of NSObject‘s init method, and so are instance methods which have to be called on an allocated instance of that class, and have to be memory managed. Creation methods which do not start with “init” are conventionally class methods, and so return autoreleased objects that don’t have to be memory managed.

2. Releasing Created Objects

The second item of the object ownership policy is:

If you own an object, you are responsible for relinquishing ownership when you have finished with it.
You relinquish ownership of an object by sending it a release message or an autorelease message (autorelease is discussed in more detail in “Delayed Release”). In Cocoa terminology, relinquishing ownership of an object is typically referred to as “releasing” an object.

If you have created the object, as established by point #1, then it is your responsibility to release it. This is very important for the maintained stability of your application, because otherwise you will leak memory, which – especially for iPhone development – can affect the performance of your application. Even if it is a small amount of memory, which you may not perceive as being worth bothering about, it is good practice to make your application as efficient as possible.

3. Memory management for objects you don’t create

The third item of the object ownership policy is:

If you do not own an object, you must not release it.

This is important, because you can “overrelease” an object, since you did not retain it initially because you do not “own” it. This can cause the object to be deallocated prematurely, and can cause your application to crash if a message is then sent to the now redundant piece of memory.

Taking ownership of objects

According to point #1, if you do not create an object, then you should not memory manage it. However, what if you are returned an autoreleased object, but want to hold onto it? An autoreleased object will be released by the autorelease pool at the end of the current event, and so if you need to keep it for a longer period of time than this, then you will essentially have a bad pointer to memory that has been relinquished.

In this case, you must take ownership of the object that has been returned to you in a memory-managed state. To do so, simply call retain on the object. This will ensure that it is not deallocated, because you are explicitly specifying that you want to keep the object around until further notice. As long as other objects that have a hold on the object (if there are any) follow the memory management guidelines then the object will stick around for as long as you need it for:

- (void)someFunction:(int)aNumber
{
    // Assume that 'string' is an instance variable; returns an autoreleased NSString
    string = [NSString stringWithFormat:@"Some number: %d", aNumber]; //Retain the string to take ownership so it won't be released
    [string retain];
}

Even though you didn’t create the object, now that you have taken ownership of the object in question, you must also release the object when you are done with it (following point #1) since you now have some form of ownership over it (whether that be full or partial).

Core Foundation classes and memory management

The Core Foundation classes have a similar ownership policy, as stated in the Memory Management Guide for Core Foundation. This is similar to the Cocoa ownership policy:

Core Foundation functions have names that indicate when you own a returned object:

  • Object-creation functions that have “Create” embedded in the name;
  • Object-duplication functions that have “Copy” embedded in the name.

If you take ownership of a Core Foundation object, you must release it when you are finished with it using CFRelease.

As noted in the guide, if you are returned a Core Foundation object through a function other than one which has “Create” or “Copy” in the name, you do not take ownership of it, and do not need to memory manage it. However, similar to the Cocoa classes, you can take ownership of  a Core Foundation object by calling CFRetain on the object. Once again, do not forget to call CFRelease once you are done with the object.

No comments

Add comment

Please enter your name and comment