Autorelease pools are automatically cleaned up after
exceptions. If you want to write exception-safe code, then
autorelease pools are a useful tool.
Exception objects themselves should be
autoreleased. +[NSException exceptionWithName:...]
and +[NSException raise:...] do this for you.
Autorelease pools can help make your other memory
exception-safe. These two patterns will correctly free memory even
if an exception is thrown. (With GC you have a third option - do
nothing - but these two also work there.)
id obj = [[[MyClass alloc] init] autorelease];
CodeThatMightThrow();
id obj = [[MyClass alloc] init];
@try {
CodeThatMightThrow();
} @finally {
[obj release];
}
The -autorelease version works like this. Autorelease
pools form a
stack. The current autorelease pool is the top of that stack. If
you call [pool drain] on an autorelease pool that is
not the
current pool, then your pool and every more recent pool after
it is destroyed.
When an exception unwinds the stack, some -drain
calls are skipped. But
those pools don't leak. Eventually the exception is caught, inside
the scope of some pool. When the [pool drain] for
that pool is
reached, the other pools bypassed by the exception are also
destroyed.
If you write your own processing loop with an autorelease pool and an
exception handler, be sure to delete your pool after you catch and
handle an exception. Otherwise the bypassed pools won't be
destroyed until you return to the next autorelease pool out, if
any.
If you write @catch or @finally
handlers, don't drain your local
autorelease pool inside the handler. The exception object might be
in that pool (or another pool inside that), and you don't want to
delete it yet. Instead, just abandon your pool and let the next
pool out take care of it. (You're free to create and destroy a new
pool inside @catch or @finally ; just
don't drain any pool that was
created before.)
In other words, don't do this:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
// stuff
} @finally {
[pool drain]; WRONG
}
Do this instead:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
// stuff
} @finally {
// cleanup things other than pool itself
}
[pool drain];
|