Delphi to Cocoa

December 21, 2007

Object Lifetime Management in Objective-C

Why am I starting with this subject? This topic wasn’t immediately intuitive and required some digging… plus it’s a vital subject. Thoroughly understanding how a language handles object lifetime management (OLM) is a “must” for any software engineer. The biggest, most obvious benefit is allowing one to write code without memory leaks or distractions. What I mean by distractions is mental effort taken away from addressing the problem at hand and putting it towards something as trivial as actually writing the code. Ideas should flow out of the brain, through the fingers, and onto the keyboard without worrying about routine things like object instantiation and destruction.

Note that the official documentation must be referred to for details. These are only notes.

OLM and Delphi

The Delphi language presents the programmer with two mechanisms. The basic mechanism is wholly manual: explicitly allocating and freeing an object. You, the programmer get to do all the work. This was the original paradigm for objects when the language first supported them.

var
  lFoo :TFoo;
begin
  lFoo := TFoo.Create;
  try
  ... work with object ... 
  finally
    lFoo.Free;
  end;
end;

The second mechanism the Delphi language presents is using interfaces and reference counting. Interfaces were added to the language later, I believe with Delphi 2. There’s some great syntactic sugar in the compiler that almost allows one to forget about OLM once an object instance has been tied to an interface. The compiler generates code to implicitly call _AddRef and _Release automatically. I say almost because while it correctly addresses >99% of OLM, there are time where it’s beneficial to circumvent the default behavior.

var
  lFoo :IFoo;
begin
  lFoo := TFoo.Create;
  ... work with object ... 
end;

In Delphi, to take advantage of interfaces, one must use classes properly equipped to support them. Ordinarily one will descend from TInterfacedObject to pick up this behavior. The root object, TObject, has no capability to work with interfaces or reference counting. This is inconvenient sometimes, but interfaces and reference-counted OLM were later additions to the language.

OLM and Objective-C

Objective-C has a different history. Its intent from the start was to extend C, giving it object-oriented capabilities. Reference-counted OLM is part of the paradigm from the ground up. Its root object, NSObject, supports reference counting. As a result this is passed to every other object.

I found a great explanation of things here. Consider it required reading. The rest are just my re-interpretation of some of the concepts in that document that I find important to remember. In other words, they stand out as important divergences from Delphi.

So what do we have thus far?

Concept Delphi Objective-C
Reference Counting Class Objects (typically) descending from TInterfacedObject and bound to an interface. All objects.*

Increment Reference Count _AddRef (normally called implicitly) retain
Decrement Reference Count _Release (normally called implicitly) release
Reference Counts Maintained automatically manually

*All objects descend from the class NSObject — the Objective-C equivalent of TObject.

So, some good news and some bad news. We gain reference counting in all objects, but lose the automatic maintenance of the reference counts. So how do we maintain the reference counts? By adhering to a set of rules, and a little glue. First the rules. They’re similar in spirit to the original Delphi OLM.

.

If Then Therefore
If you allocate it… you own it, therefore you must call release.
If you didn’t allocate it… you don’t own it, therefore you must not call release.
If you didn’t allocate it… but you want to keep it around, you must call retain and release at the appropriate times.

Note that the “appropriate times” are the same times that one might manually call _AddRef() and _Release() in Delphi to keep a reference-counted object around (without using interfaces).

The specific rules are summarized here. Note that there are conventions for method naming that should be adhered to to avoid problems later.

Autorelease Pools

There are cases where reference counting can be a bit tricky. In Delphi these are ordinarily hidden from view through compiler magic. In Objective-C there’s an interesting work-around: autorelease pools. (See link for official documentation.) The autorelease pools are a stack-oriented hierarchy of object-specific memory pools to which objects may be attached. One attaches objects to them to keep them around for disposal at a future time. When one of these pools are released, all objects with a zero reference count are freed, and all other objects are moved to the next pool in the stack.

One can use (in interesting ways) autorelease pools to manage when autorelease objects are released.

Summary

  1. You own the object if you call alloc*, new*, or *[Cc]opy*. Be sure to call release.
  2. If you otherwise received an object, autorelease has already been called on it, pushing onto the autorelease pool. It is safe to use in your scope (as the caller).
  3. If you wish to keep a handle to an object “otherwise received” (see #2), call retain. When appropriate, dispose of the handle via release or autorelease as appropriate.
Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: