- 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
Avoiding Retain Cycles
The problem with pure reference counting is that it doesn’t detect cycles. If you have two objects that retain references to each other, then neither will ever be freed.
In general, this is not a major problem. Objective-C data structures tend to be acyclic, but there are some common cases where cycles are inevitable. The most common is the delegation pattern. In this pattern, an object typically implements some mechanisms and delegates policy to another object. Most of AppKit works in this way.
The delegate needs a reference to the object, and the object needs a reference to its delegate. This immediately creates a cycle. The common idiom that addresses this problem is that objects do not retain their delegates. If you pass an object as an argument to a -setDelegate: method, you need to make sure that some other object holds a reference to it, or it will be deleted prematurely.
With ARC, you have two choices: You can either mark the instance variable as __weak or as __unsafe_unretained. The former is safer, because it ensures that there is no chance of a dangling pointer: When the delegate is destroyed, the instance variable will be set to nil.
There are two disadvantages of using a weak pointer. The first is portability. Weak pointers work on iOS 5, Mac OS X 10.7, and with GNUstep, but they don’t work on older versions of iOS or Mac OS X. The other disadvantage is performance. Every access to a weak pointer goes via a helper function. This checks that the object was not in the process of deallocation and retains it if it is still valid, or returns nil if it is not.
In contrast, unsafe unretained pointers are just plain pointers. They are cheap to access and work on any deployment target. Their disadvantage is that you are responsible for ensuring that you don’t try to access them after the pointee has been deallocated.
A good compromise is to use weak pointers when debugging and unsafe unretained pointers for deployment. Add debug assert statements checking that the pointer is not nil before you send it any messages, and you’ll end up with a helpful error, rather than a crash, if you have bugs.