In memory-managed Objective-C code, a Cocoa object exists over a life span which, potentially at least, has
distinct stages. It is created, initialized, and used (that is, other objects send messages to it). It is possibly
retained, copied, or archived, and eventually it is released and destroyed. The following discussion charts
the life of a typical object without going into much detail—yet.
Let’s begin at the end, at theway objects are disposed ofwhen garbage collection is turned off. In this context
Cocoa and Objective-C opt for a voluntary, policy-driven procedure for keeping objects around and disposing
of them when they’re no longer needed.
This procedure and policy rest on the notion of reference counting. Each Cocoa object carries with it an
integer indicating the number of other objects (or even procedural code sites) that are interested in its
persistence. This integer is referred to as the object’s retain count (“retain” is used to avoid overloading the
term “reference”). When you create an object, either by using a class factory method or by using the alloc
or allocWithZone: class methods, Cocoa does a couple of very important things:
■ It sets the object’s isa pointer—the NSObject class’s sole public instance variable—to point to the
object’s class, thus integrating the object into the runtime’s view of the class hierarchy.
■ It sets the object’s retain count—a kind of hidden instance variable managed by the runtime—to one.
(The assumption here is that an object’s creator is interested in its persistence.)
After object allocation, you generally initialize an object by setting its instance variables to reasonable initial
values. (NSObject declares the init method as the prototype for this purpose.) The object is now ready to
be used; you can send messages to it, pass it to other objects, and so on.
Note: Because an initializer can return an object other than the one explicitly allocated, the convention is to
nest the alloc message expression in the init message (or other initializer)—for example:
id anObj = [[MyClass alloc] init];
When you release an object—that is, send a releasemessage to it—NSObject decrements its retain count.
If the retain count falls fromone to zero, the object is deallocated. Deallocation takes place in two steps. First,
the object’s deallocmethod is invoked to release instance variables and free dynamically allocatedmemory.
Then the operating system destroys the object itself and reclaims the memory the object once occupied.
Important: You should never directly invoke an object’s dealloc method.
What if you don’t want an object to go away any time soon? If after receiving an object from somewhere
you send it a retainmessage, the object’s retain count is incremented to two. Now two releasemessages
are required before deallocation occurs. Figure 2-4 depicts this rather simplistic scenario.
Figure 2-4 The life cycle of an object—simplified view
Of course, in this scenario the creator of an object has no need to retain the object. It owns the object already.
But if this creator were to pass the object to another object in a message, the situation changes. In an
Objective-C program, an object received from some other object is always assumed to be valid within the
scope it is obtained. The receiving object can send messages to the received object and can pass it to other
objects. This assumption requires the sending object to “behave” and not prematurely free the object while
a client object has a reference to it.
If the client object wants to keep the received object around after it goes out of programmatic scope, it can
retain it—that is, send it a retainmessage. Retaining an object increments its retain count, thereby expressing
an ownership interest in the object. The client object assumes a responsibility to release the object at some
later time. If the creator of an object releases it, but a client object has retained that same object, the object
persists until the client releases it. Figure 2-5 illustrates this sequence.
Instead of retaining an object you could copy it by sending it a copy or copyWithZone: message. (Many,
if notmost, subclasses encapsulating some kind of data adopt or conformto this protocol.) Copying an object
not only duplicates it but almost always resets its retain count to one (see Figure 2-6). The copy can be shallow
or deep, depending on the nature of the object and its intended usage. A deep copy duplicates the objects
held as instance variables of the copied object while a shallow copy duplicates only the references to those
In terms of usage, what differentiates a copy from a retain is that the former claims the object for the sole
use of the new owner; the new owner can mutate the copied object without regard to its origin. Generally
you copy an object instead of retaining it when it is a value object—that is, an object encapsulating some
primitive value. This is especially true when that object is mutable, such as an NSMutableString. For
immutable objects, copy and retain can be equivalent and might be implemented similarly.
You might have noticed a potential problem with this scheme for managing the object life cycle. An object
that creates an object and passes it to another object cannot always know when it can release the object
safely. There could be multiple references to that object on the call stack, some by objects unknown to the
creating object. If the creating object releases the created object and then some other object sends amessage
to that now-destroyed object, the program could crash. To get around this problem, Cocoa introduces a
mechanism for deferred deallocation called autoreleasing.
Autoreleasing makes use of autorelease pools (defined by the NSAutoreleasePool class). A autorelease
pool is a collection of objects within an explicitly defined scope that are marked for eventual release.
Autorelease pools can be nested. When you send an object an autorelease message, a reference to that
object is put into the most immediate autorelease pool. It is still a valid object, so other objects within the
scope defined by the autorelease pool can send messages to it. When program execution reaches the end
of the scope, the pool is released and, as a consequence, all objects in the pool are released as well (see
Figure 2-7). If you are developing an application you may not need to set up an autorelease pool; the
Application Kit automatically sets up an autorelease pool scoped to the application’s event cycle.
iPhoneOS Note:Because on iPhone OS an application executes in amorememory-constrained environment,
the use of autorelease pools is discouraged in methods or blocks of code (for example, loops) where an
application creates many objects. Instead, you should explicitly release objects whenever possible.
So far the discussion of the object life cycle has focused on the mechanics of managing objects through that
cycle. But a policy of object ownership guides the use of these mechanisms. This policy can be summarized
■ If you create an object by allocating and initializing it (for example, [[MyClass alloc] init]), you
own the object and are responsible for releasing it. This rule also applies if you use the NSObject
convenience method new.
■ If you copy an object, you own the copied object and are responsible for releasing it.
■ If you retain an object, you have partial ownership of the object and must release it when you no longer
Pool alloc] init];
¦ If you receive an object from some other object, you do not own the object and should not release it.
(There are a handful of exceptions to this rule,which are explicitly noted in the reference documentation.)
As with any set of rules, there are exceptions and “gotchas”:
¦ If you create an object using a class factorymethod (such as the NSMutableArray arrayWithCapacity:
method), assume that the object you receive has been autoreleased. You should not release the object
yourself and should retain it if you want to keep it around.
■ To avoid cyclic references, a child object should never retain its parent. (A parent is the creator of the
child or is an object holding the child as instance variable.)
Note: “Release” in the above guidelines means sending either a release message or an autorelease
message to an object.
If you do not follow this ownership policy, two bad things are likely to happen in your Cocoa program.
Because you did not release created, copied, or retained objects, your program is now leaking memory. Or
your program crashes because you sent a message to an object that was deallocated out from under you.
And here’s a further caveat: debugging these problems can be a time-consuming affair.
A further basic event that could happen to an object during its life cycle is archiving. Archiving converts the
web of interrelated objects that comprise an object-oriented program—the object graph—into a persistent
form (usually a file) that preserves the identity and relationships of each object in the graph. When the
program is unarchived, its object graph is reconstructed from this archive. To participate in archiving (and
unarchiving), an object must be able to encode (and decode) its instance variables using the methods of the
NSCoder class. NSObject adopts the NSCoding protocol for this purpose. Formore information on the archiving
of objects, see “Object Archives” .
Tagged: Iphone Document