Objective-C Memory Management

Regardless of what your language background is, memory management in Objective-C can be a bit difficult to get a handle on. I won’t claim to be an expert on the topic, since I’m still learning myself, but here’s a few of the things I’ve learned while trying to unravel the complexity lately:

There’s a seeming mass of various methods with which you can message NSObjects and any class object that is extend from NSObject, including: alloc, dealloc, retain, release, autorelease, and finalize. But just what do all these mean?

First of all, you need to know that Objective-C has garbage collection capability. If you don’t know what garbage collection is, do a Google Search and familiarize yourself with the topic. Once you’re familiar with the wonders of garbage collection, you need to know that Objective-C may not always use it…

So, as best as I can tell, here’s what the above methods do:

  • alloc: Allocates a block of memory the size necessary for a new instance of an object, returning an uninitialized instance of the object – the object should be initialized using a class initializer after being allocated.
  • dealloc: Automatically called when a block of memory is to be released – ONLY if garbage collection is NOT enabled. Classes should release – not dealloc any objects allocated by the object from here, as they should no longer be needed. Finally, subclasses should also call the superclass dealloc method. This method should NOT be called manually
  • retain: Increments a “retain” count for the object – if the retain count of an object is greater than zero, it will not be garbage collected, autoreleased, dealloced, or finalized in any case.
  • release: Decrements a “retain” count for the object – when the retain count of an object becomes zero, it is free to be garbage collected, autoreleased, and dealloced or finalized.
  • autorelease: Adds the object to the “innermost” autorelease pool; the object will be released when the autorelease pool schedules the next release. When the schedule autorelease occurs, the “retain” count will be decremented and the object removed from the autorelease pool. Calling autorelease multiple times will add the object to the autorelease pool multiple times, and thus call release the same number of times before the object is removed from the pool. If the “retain” count reached zero, the object will be dealloced.

That’s the ugly… Is general, things are actually quite simple:

1) If an object is created using alloc, it will have a retain count of 1, and should be released using release when the object is no longer needed.

2) Calling retain will increment the retain counter; release will need to be called the same number of times to bring the retain count to pre-retain state. (Excluding autorelease scenarios)

Using native Objective-C methods for C Callbacks

For the modern Macintosh programmer, given the incredible power of the Objective-C programming language combined with the fact that you can inline C code directly in the Objective-C code, there are few things left wanting … almost.

One of these stickly issues is the use of C callbacks; passing the reference of a function to a function in order to later make use of it. If you’re writing up your own code from scratch this really isn’t going to come up. But if you want to use a C library in your Objective-C code, especially if you want to call an object method instead of a C function for the callback, it’s a problem very likely to come up.

Because of the Object-Oriented nature of Objective-C, it’s essentially impossible to make a callback to an object method. (Think about it; the method is part of an object instance, and because of the dynamic nature of an object, it’s impossible for the compiler to know the reference to an instance of an object) Thanks, however, to the magic of dynamic typing, even this can be done without too much problem. The one caveat is that the library (or other implementation requiring callbacks) must have the option to pass an arbitrary data reference to the same callback. Here’s how it works:

// Dummy callback object - to prevent compiler warnings
@interface CallbackObject
- (void) updateObject: (void *)data;

@implementation CallbackObject
- (void) updateObject: (void *)data { }

// The C function passed as the callback
static void updateObjectCallback(void *ptr, void *parent)
CallbackObject *parentObject = (CallbackObject *)parent;
[parentObject updateObject: ptr];

First, some background: In Objective-C, objects are generally passed around as references. For example, if we’re passing around an instance of NSObject, this will generally be in the form of an (NSObject *). In a special case, the variable self is also a reference to the current instance of itself (as opposed to the actual data). This is very useful to us for dealing with callbacks.

Consider the case of a library that manipulates an array of items. The library has a function requiring a callback that will allow you to perform some custom manipulation of each item (The callback being the function that performs the manipulation on each individual item). So, when calling the callback function, the library will pass the item reference as the first parameter, and the arbitrary reference as the second.

This is how the above example works; the callback function has two parameters: the first being a reference to a particular item, and the second being an arbitrary reference, which we decide to use as the reference to the instance of an object. We then can cast the second arbitrary reference to a type of an object containing the callback method we want to use.

But… Why the “Dummy” CallbackObject? It doesn’t even do anything? Exactly. In fact, it’s important to note that the code will work without the “Dummy” CallbackObject. We could have cast the reference to an NSObject *, or, in fact, any Objective-C object. The only reason we use CallbackObject is to prevent compiler warnings that the given object may not respond to the updateObject method. (We already know that the updateObject will exist when we call it) More on why we used this approach in a moment…

Here’s the code in a class that actually makes use of the callback function:

- (void) updateObjects:(NSObject *) object;
libUpdateObjects(library->objectList, updateObjectCallback, self);

- (void) updateObject: (void *)item
// Do stuff with the item here

Now we’ve come full circle. The class calls the updateObjects method, in turn invoking the C library function libUpdateObjects, which in turn calls updateObjectCallback on each item, passing the reference to each item, along with the reference to the current object (self).

That goes up to our previously defined callback function, which casts the reference into an object instance of type CallbackObject, and then sends a message to the method updateObjects in that instance. Note that because of the dynamic nature of Objective-C, the updateObject method in CallbackObject never gets called.

Finally, with each item, it’s back in the current instance, doing whatever is supposed to be done with the item in updateObject; and as a result, all the class variables, etc. are fully available to the method!

Granted, this could be set up slightly simpler, however, the beauty of this approach is that any class reference can be passed into the callback – there’s no limitation that requires that “self” be passed as the object reference. Suppose you had another class that also had an updateObject method – you could without reserve pass the reference to that object. (It goes for granted that the method needs to deal with the same type of ‘item’)

Finally, this may also be obvious, but if you want to have multiple callback routines, you’ll need to set up a separate callback template and method for each one. So, that’s how to use native Objective-C methods for C Callbacks.