- Inherits from:
- NSObject
- Conforms to:
- NSObject
- (NSObject)
Declared in:
- Foundation/NSAutoreleasePool.h
The NSAutoreleasePool class is used to implement the Foundation Kit's autorelease mechanism. An NSAutoreleasePool object simply contains objects that have received an autorelease message, and when deallocated sends a release message to each of those objects. An object can be put into the same pool several times, and receives a release message for each time it was put into the pool. Thus, sending autorelease instead of release to an object extends the lifetime of that object until the pool itself is released or longer if the object is retained. This class specification contains information on fine-tuning your application's handling of autorelease pools.
You create an NSAutoreleasePool with the usual alloc and init messages, and dispose of it with release (an exception will be raised if you send autorelease or retain to an autorelease pool). An autorelease pool should always be released in the same context (invocation of a method or function, or body of a loop) that it was created. When a thread terminates, it automatically releases all of the autorelease pools associated with itself.
Autorelease pools can be nested, so you can include them in
any function or method. For example, a main()
function
may create an autorelease pool and call another function that creates
another autorelease pool. Or a single method might have an autorelease
pool for an outer loop, and another autorelease pool for an inner
loop. Each thread in a program maintains autorelease pools on a
stack; the most recently created (and unreleased) autorelease pool
is the top pool on the stack. The ability to nest autorelease pools
is a definite advantage, but there are side effects when exceptions
occur (see "Implications of Nested Autorelease Pools" ).
NSAutoreleasePools are automatically created and destroyed in applications based on the Application Kit, so your code normally doesn't have to worry about them. (The Application Kit creates a pool at the beginning of the event loop and releases it at the end). There are two cases, though, where you might wish to create and destroy your own autorelease pools. If you're writing a program that's not based on the Application Kit, such as a command-line tool, there's no built-in support for autorelease pools; you must create and destroy them yourself. Also, if you write a loop that creates many temporary objects, you might wish to create an NSAutoreleasePool inside the loop to dispose of those objects before the next iteration.
Enabling the autorelease mechanism in a program that's not based on the Application Kit is easy. Many programs have a top-level loop where they do most of their work. To enable the autorelease mechanism you create an NSAutoreleasePool at the beginning of this loop and release it at the end. An autorelease message sent in the body of the loop automatically puts its receiver into this pool.
Your main()
function
might look like this:
void main() { NSArray *args = [[NSProcessInfo processInfo] arguments]; unsigned count, limit = [args count]; for (count = 1; count < limit; count++){ NSAutoreleasePool *pool =[[NSAutoreleasePool alloc] init]; NSString *fileContents; NSString *fileName; fileName = [args objectAtIndex:count]; fileContents = [[NSString alloc] initWithContentsOfFile:fileName]; [fileContents autorelease]; /* Process the file, creating and autoreleasing more objects. */ [pool release]; } /* Do whatever cleanup is needed. */ exit (EXIT_SUCCESS); }
This program processes files passed in on the command line.
The for
loop processes
one file at a time. An NSAutoreleasePool is created at the beginning
of this loop and released at the end. Therefore, any object sent
an autorelease message inside the for
loop,
such as fileContents, is added to pool, and
when pool is released at the end
of the loop those objects are also released.
Similarly, NSAutoreleasePools can be created inside any loop, even in a program based on the Application Kit, that creates and releases many objects during each iteration.
It's common to speak of autorelease pools as being nested because of the enclosure evident in code; for instance, you can have an autorelease pool in an outer loop that contains an inner loop with its own autorelease pool. But you can also think of nested autorelease pools as being on a stack, with the "inmost" autorelease pool being on top of the stack. As noted earlier, this is actually how nested autorelease pools are implemented: Each thread (NSThread) in a program maintains a stack of autorelease pools. When you create an autorelease pool, it is pushed onto the top of the current thread's stack. Autoreleased objects-that is, objects which have received an autorelease message or which are added through the addObject: class method-are always put in the autorelease pool at the top of the stack.
Released autorelease pools, if not on the top of the stack, will cause all (unreleased) autorelease pools above them on the stack to be released, along with all their objects. If you neglect to send release to an autorelease pool when you're finished with it (something not recommended), it will be released when one of the autorelease pools in which it nests is released.
This behavior has implications for exceptional conditions. If an exception occurs, and the thread suddenly transfers out of the current context, the pool associated with that context is released. However, if that pool is not the top pool on the thread's stack, all the pools above the released pool are also released (releasing all their objects in the process). The top autorelease pool on the thread's stack then becomes the pool previously underneath the released pool associated with the exceptional condition. Because of this behavior, exception handlers do not need to release objects that were sent autorelease. Neither is it necessary or even desirable for an exception handler to send release to its autorelease pool, unless the handler is re-raising the exception.
By creating an NSAutoreleasePool instead of simply releasing objects, you extend the lifetime of temporary objects to the lifetime of that pool. After an NSAutoreleasePool is deallocated, you should regard any object that was autoreleased while that pool was active as "disposed of", and not send a message to that object or return it to the invoker of your method.
If you must use a temporary object beyond an autorelease context, you can do so by sending a retain message to the object within the context and then send it autorelease after the pool has been released as in:
- findMatchingObject:anObject { id match = nil; while (match == nil) { NSAutoreleasePool *subpool = [[NSAutoreleasePool alloc] init]; /* Do a search that creates a lot of temporary objects. */ match = [self expensiveSearchForObject:anObject]; if (match != nil) [match retain]; /* Keep match around. */ [subpool release]; } return [match autorelease]; /* Let match go and return it. */ }
By sending retain to match while subpool is in effect and sending autorelease to it after subpool has been released, match is effectively moved from subpool to the pool that was previously active. This extends the lifetime of match and allows it to receive messages outside the loop and be returned to the invoker of findMatchingObject:.
- Adding an object to the current pool
- + addObject:
- Adding an object
- - addObject:
+ (void)addObject:(id)anObject
See Also: - addObject:
- (void)addObject:(id)anObject
See Also: + addObject: