- Retaining and Releasing
- Assigning to Instance Variables
- Automatic Reference Counting
- Returning Objects via Pointer Arguments
- Avoiding Retain Cycles
- Migrating to ARC
- Autorelease Pools
- Using Autoreleased Constructors
- Autoreleasing Objects in Accessors
- Supporting Automatic Garbage Collection
- Interoperating with C
- Understanding Object Destruction
- Using Weak References
- Allocating Scanned Memory
Aside from cycles, the biggest problem with reference counting is that there are short periods when no object really owns a particular reference. In C, deciding whether the caller or callee is responsible for allocating memory is a problem.
In something like the sprintf() function, the caller allocates the space. Unfortunately, the caller doesn’t actually know how much space is needed, so the snprintf() variant was added to let the callee know how much space is available. This can still cause problems, so the asprintf() version was added to let the callee allocate the space.
If the callee is allocating the space, who is responsible for freeing it? The caller, presumably, but because the caller didn’t create it, anything that checks for balanced malloc() and free() calls will fail to spot the leak.
In Objective-C, this problem is even more common. Lots of methods may return temporary objects. If you’re returning a temporary object, it needs to be freed, but if you’re returning a pointer to an instance variable, it doesn’t. You could retain such a pointer first, but then you need to remember to release every single object that is returned from a method. This quickly gets tiresome.
The solution to this problem is the autorelease pool. When you send an object an -autorelease message, it is added to the currently active NSAutoreleasePool instance. When this instance is destroyed, every object added to it is sent a -release message.
The -autorelease message is a deferred -release message. You send it to an object when you no longer need a reference to it but something else might.
If you are using NSRunLoop, an autorelease pool will be created at the start of every run loop iteration and destroyed at the end. This means that no temporary objects will be destroyed until the end of the current iteration. If you are doing something that creates a lot of temporary objects, you may wish to create a new autorelease pool, like so:
id pool = [NSAutoreleasePool new]; [anObject doSomethingThatCreatesObjects]; [pool drain];
Note that you send an autorelease pool a -drain message rather than a release message when you destroy it. That is because the Objective-C runtime will ignore -release messages when you are in garbage collected mode. The -drain message in this mode provides a hint to the collector, but does not destroy the pool, when you are in garbage collected mode.
In OS X 10.7, Apple made autorelease pools part of the language. Programs that explicitly reference the NSAutoreleasePool class are considered invalid in ARC mode and the compiler will reject them. The replacement is the @autoreleasepool construct. This defines a region where an autorelease pool is valid. In non-ARC mode, this will insert exactly the same code as the above snippet. In ARC mode, it inserts calls to the objc_autoreleasePoolPush() and objc_autoreleasePoolPop() functions, which do something similar.