Exception safety in Objective-C



Exceptions in Objective C are implemented using the C primitive:
longjmp(). Objective-C is not C++. You may have many layers of method
call between the code that raises the exception and the method that
catches it. It is very easy to write a memory leak.

Search your source code for methods that are not setters, and are not
-(void)dealloc but which call -(void)release.

A common pattern is:
MyItem *item = [[MyItem alloc] init];
[item setPart:[factory makePart]]; // calls many other things.
[myArray addObject:alteredItem];
[item release];


Now, if [factory makePart] throws an exception, the [item release] will
never get called and you'll have a memory leak. The usual fix is to get
rid of the explicit [item release] and instead create item with:

MyItem *item = [[[MyItem alloc] init] autorelease];

That does work. If -(MyItem*)makePart; throws, item will still get
released, when the autorelease pool is drained.

But that doesn't work for autorelease pools. If you are creating
autorelease pools, and something you write might call something that
might someday be maintained to throw exceptions, you must write not the
usual:

NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
[self doSomeWork]; // calls many other things.
[pool release];


but instead the correct:

@try {
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
[self doSomeWork];
}@finally{
[pool release];
}

(Note that you don't need the @catch part.)
Written this way, and if doSomeWork calls something that throws, you
pool will get drained as the stack gets unwound on its way up to the
handler.

Lastly, If you are writing in Objective-C++, be aware that C++
exceptions and Objective-C exceptions don't mix. If your program might
ever be maintained to throw either kind, then, at the points where the
program switches from one language to the other, it must catch the inner
exception in one language, and rethrow it as the equivalent exception in
the other language. (And note as the stack is unwound the exception may
be rethrown from C++ to Objective-C and back multiple times.)

Note that any creation of an object, even convenience methods that
return autoreleased objects, calls - (id)[alloc], which in turn can
throw an NSMallocException, and be very afraid.

(In the real world, we are all in denial about this last one.)
-- David Phillip Oster

(I posted earlier version of this posting as a comment on the end of
http://www.macdevcenter.com/pub/a/mac/2007/07/31/understanding-exceptions
-and-handlers-in-cocoa.html )
.