Objective-C on iOS has no garbage collector, so it is up to the programmer to make sure that memory is properly freed once an object is no longer needed. On the other hand, Objective-C on the Mac does have a garbage collector (in Objective C 2.0). This blog post focuses on how to manage memory in the absence of a garbage collector.
When managing memory manually, two major issues to watch out for are premature deallocation and memory leaks.
Cocoa Touch framework uses manual reference counting to manage memory on the iOS devices. Reference counting works on the principle that once created, every object has an owner. During its existence, its owner may change and it may even have more than one owners. When the number of owners for an object drops to zero, it deallocates itself to free up the memory being used.
retain & release
Owners are tracked via retain counts. When an object is created it always has a retain count of 1. To own an object its retain count is incremented via the
retain message. On the other hand, when the object is no longer needed its ownership is relinquished by decrementing the retain count via the
release message. When the count reaches zero, the object sends itself the
dealloc message and returns all the memory back to the heap.
autorelease marks an object for future release (delayed release). When an object is sent the autorelease message, it is added to an instance of
NSAutoreleasePool. The Autorelease pool keeps track of all the objects that have been sent the
autorelease message. This pool is drained periodically, at which time all the objects within it are sent the release message.
autorelease is really handy when the creator of an object (e.g. a factory) simply creates the object and returns it to the caller. At this point, the creator has nothing to do with the object anymore, so it is up to the caller to retain the returned object in order to continue using it.
An Example - A Ticket class
Let us work through an example to see manual memory management in action. Suppose I am writing a ticketing framework, and I have a Ticket entity. The header file for Ticket looks as:
1 2 3 4 5 6 7 8 9 10 11
And the implementation file for Ticket looks as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
There are three memory management points to note here:
dealloc, an object must release all its instance variables first. Then it should go up its class hierarchy and release any instance variables of its superclass. We should never directly send the
deallocmessage to instance variables, as some other objects might still have references to those variables.
A setter must retain the value passed in before it releases the old value, as
ticketIdcould be pointers to the same object.
ticketWithId:method creates a ticket and simply returns it to the caller. It has no use for the
newTkt, but it owns
newTktby virtue of creating it. At this point, if
newTktwere released before method exit, then the caller would get a pointer to unallocated heap. To avoid this, we put the
newTkton the autorelease pool. Periodically, the autorelease pool is drained and all the objects it it are sent the
releasemessage thus decrementing the retain count.
ticketWithId: method is saying that it does not want to be the owner for
newTkt and puts that responsibility on the caller. If the caller wants to hold on to
newTkt once it is returned, it must send it the
Using the Ticket class:
1 2 3 4 5 6 7 8
At this point, the retain count for
tkt is 1. Moreover, since the
processTicketWithId: method created the
tkt object, it is now the owner and thus is responsible for cleaning it up before this method exits. Clean up is done by sending it the
Let’s see another example:
1 2 3 4 5 6 7 8 9
In this example, the memory for
tkt wasn’t allocated by
processTicketWithId method, so it doesn’t own the
tkt object. However, as we’ve seen in the implementation of the Ticket class, the
ticketWithId: method created the Ticket object and added it to the autorelease pool. In order to continue using
tkt, we must retain it so that even if it is drained from the autorelease pool, we can still continue to use the
tkt object. Once done, we need to clean up and send the release message.
Summary of Memory Management Rules for Objective-C:
Rule-1: If you get/create the object from
copy, you must
release it when done.
Rule-2: If you get the object any other way, assume that it has been autoreleased. If you want to hold on to this object, send it the
Rule-3: If you
retain an object, you must balance every
retain with a
Rule-4: Never send the
dealloc message to an object directly. Others might be holding references to this object, and if deallocated, they’ll be left with pointers to unallocated memory.