- 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
Returning Objects via Pointer Arguments
From: writeback.m
In ARC mode, pointer-to-pointer arguments are somewhat complicated. These are typically used for two things, either passing arrays or returning objects. If you are passing an array down the stack, then you should make sure that you declare it as const. This tells the compiler that the callee will not perform any assignments to it, so ARC can pass the array without any complex interaction.
If you are returning an object via this mechanism, ARC produces some fairly complex code. In the example at the start of this section, the call to writeBack() generates code that is roughly equivalent to this:
id tmp = [object retain]; writeBack(&tmp); [tmp retain]; [object release]; object = tmp;
In writeBack(), the new object will be autoreleased before storing it in the temporary value. This means that, at the end of this, object contains an owning reference to the new object.
If you declared object as __autoreleasing id, the generated code is a lot simpler. This will simply autorelease the value initially stored in object, which will have no effect because the initial value for all object pointers—even with automatic storage—is nil, and will pass the pointer directly and expect the callee to store a non-owning (autoreleased) pointer in it, if it modifies it.
When you run this example, you’ll see that the weak reference is only zeroed when the autorelease pool is destroyed. The writeBack() function stores an autoreleased object into the passed pointer in all cases, and never releases the passed value. The caller is always responsible for ensuring that the value passed in is a non-owning reference, which it does either by ensuring that it’s a pointer to an autoreleased object or a copy of a pointer to a retained object.
If you instead mark the parameter out (only allowed on method parameters, not C function parameters) then the callee guarantees that it will not read the value, so the compiler will skip the step where it makes a copy of the pointer in object before the call.
If you need to pass multiple objects up the stack, then you should probably return an NSArray instance. There are some alternatives, but they are sufficiently complex that it’s simply not worth the effort: they’re easy to get subtly wrong and spend ages debugging, and if you do manage to get it right, you’ll probably find it’s slower than using an NSArray.
If you are passing multiple values down the stack, then you should declare an array type with an explicit ownership qualifier for the parameter, not a pointer type. For example, __unsafe_unretained id [] instead of id *. This ensures that the writeback mechanism is not used.