Pointer Arguments
The only slightly tricky bit of ARC is passing pointers to object pointers. There are two reasons to do this: passing an array, or passing a pointer for write-back. With ARC, the compiler needs to know which of these you intend, because the semantics differ.
If you've looked at the Lion API diffs for the Foundation framework, then you've probably noticed a lot of changes like this:
// 10.6 - (id)initWithObjects:(const id *)objects count:(NSUInteger)cnt // 10.7 - (id)initWithObjects:(const id[])objects count:(NSUInteger)cnt
With ARC, id* now means pointer-used-to-return-an-object, while id[] means array-of-objects. In non-ARC mode, you are supposed to know the difference from the documentation and write your memory management code correctly. With ARC, the compiler must do this for you. Consider something like this:
id value = someValue; [object getValue: &value];
For this to work, the compiler has to be able to tell something about what will happen to this array in the called method. If it's const, then the caller knows that the callee won't release or assign to any of the elements in the array, so it can just pass it as a pointer. If it's using it to return some values, then the value needs to be qualified as __strong or __autoreleasing.
If it's an autoreleasing parameter, and you also qualify value as __autoreleasing, then this is simple. Again, it just passes the pointer: It will only have autoreleased values stored in it, so it's safe. This is a lot more complicated for __strong variables with unqualified pointers. The above code would generate something like this:
id value = someValue; id tmp = value; [object getValue: &tmp]; [tmp retain]; [value release]; value = tmp;
This code ensures that the object that value points to is always retained and the old value is unretained, irrespective of what the called method does with it, as long as whatever it does is balanced.
What's Next
In the next article, we'll look at how ARC interoperates with C and C++, and how some of the optimizations work. Methods like -getObjects:range: have all been changed with 10.7 so that the first argument is __unsafe_unretained id[], instead of an id*. This means that the compiler will not add any retain or release operations when you use these methods. This is intentional, because these are most commonly used by heavily optimized code. As with non-ARC mode, this means that you must be careful about removing objects from a collection after calling a method like this. Doing so can cause it to be released, making your buffer contain dangling pointers.