Documentation: Languages

Objective-C

Objective-C, often referred to as ObjC and sometimes as Objective C or Obj-C, is a reflective, object-oriented programming language which adds Smalltalk-style messaging to C. Today it is used primarily on Mac OS X and GNUstep, two environments based on the OpenStep standard (although Mac OS X is OpenStep incompatible), and is the primary language used for the NeXTSTEP, OPENSTEP, and Cocoa application frameworks. Generic Objective-C programs which do not make use of these libraries can also be compiled for any system supported by gcc, which includes an Objective-C compiler. via Wikipedia

For an introductory tutorial on using Objective-C in the context of GNUstep, and thus Étoilé, visit http://www.otierney.net/objective-c.html

Memory Management

One source of problems for many new Objective-C users is memory management. If you come from Java or Smalltalk, you will be used to memory being managed for you - you create objects, but the system frees them when you stop referencing them. If you come from C or C++, you will be used to convoluted dances to ensure that only one object is 'owning' another. Objective-C falls somewhere in the middle, with manual reference counting.

An object has a reference count (often called a retain count) and when this reaches zero the object is sent a dealloc message, which cause it to free itself. At the simplest level, every time you want to keep a pointer to an object, you need to send it a retain message:

a = [anObject retain];

In general, this only applies if you want to keep the object around for longer than the current lexical scope (typically a method or function). If you are assigning an object to a local variable, then you can just do a straight assignment:

a = anObject;

Since you only need to use retain for assigning to instance variables or globals, it is likely that a lot of the time the variable will already be pointing to something else. To do the assignment you therefore need to tell the old object you no longer want to retain a pointer to it, by releaseing it:

[a release];
a = [anObject retain];

Looks simple? Well, there's a catch. What if a is already anObject? In this case, you might have just free'd the object and then assigned an invalid pointer to a. Instead, you need to do:

id tmp = [anObject retain];
[a release];
a = tmp;

Note that tmp is not guaranteed to be anObject. In most cases it will be, but occasionally an object will return a copy of itself or a proxy when you send it a -retain message. If you store anObject instead of tmp then it will almost certainly work - and then be incredibly hard to debug in the few cases where it doesn't. Fortunately, there is a macro provided by GNUstep to simplify the whole thing:

ASSIGN(a, anObject);

Now, reference counting has one major problem, which is what happens when you return a pointer to an object? If you retain the object before returning it, your caller needs to remember to release it, which means you need to track whether you keep references to things a long time after the call. This gets very messy, very quickly. Fortunately, OpenStep has a simple solution to this: NSAutoreleasePool.

When you send an object an autorelease message, it is added to the current autorelease pool. When this pool is destroyed, the object is released. Autorelease pools are always created and destroyed in the same lexical scope and one is always created at the start of every run loop and destroyed at the end. If you want to return an object that you don't keep any references to, you do this:

return [a autorelease];

The autorelease message says 'I don't want this anymore, but don't destroy it quite yet'. At the end of the run loop, the object will be sent a release message. If anyone has retained it, their pointer will still be valid, otherwise it will be destroyed.

So, what happens when you create an object? There are two ways of creating objects typically:

NSString *s1 = [[NSString alloc] init];
NSString *s2 = [NSString string];

If you create an object with +alloc then it will have a retain count of 1. You need to send it a release or autorelease message if you don't want to keep hold of it. If you create an object with any other constructor then it will have a retain count of 1 and an autorelease count of 1, meaning that it will be automatically destroyed in the future unless you retain it.

One last thing to remember: -dealloc methods. Every object that has any instance variables should implement something like this:

- dealloc
{
    [a release];
    [b release];
    [super dealloc];
}

Don't forget the call to [super dealloc] - it is -dealloc in NSObject that actually destroys the object. Also, make sure you send a release not a dealloc message to each of the instance variables: this is an easy typo to make if you are not thinking, but one which causes bugs that are very hard to track down.

If you are using Smalltalk, -dealloc methods are automatically inserted for you, as are all retain and release messages where they are needed.