Can someone please explain to me the purpose of having __autoreleasing
in the following sample code block?
- (void)execute:(NSError * __autoreleasing *)error {
// do stuff, possibly assigning error if something went wrong
}
I removed the __autoreleasing
and everything still seems to compile/run fine. I started using obj-c post ARC so I never really learned/understood all those double underscore thingamajigs. I've read the ARC transition guide, but I don't fully understand their NSError example.
Consider how ARC works with variables - each reference variable has a mode (implicit or explicit): strong, weak, etc. This mode let's ARC know how to handle reads and writes to that variable; e.g. for a strong variable reading requires no additional action while writing requires releasing the existing reference in the variable before it is replaced by the new one. ARC needs to know the mode of any variable in order to function.
Now consider variables that themselves are passed by reference, e.g. for your
execute
you'll have a call along the lines of:and the body of
execute
will contain an assignment along the lines of:Now for that indirect assignment ARC needs to know the mode of the referenced variable so it knows how to read and write. That is what the
__autoreleasing
is in the declaration, it tells ARC that it has been passed a reference to a variable whose mode is autoreleasing, and that tells ARC how to read and write the contents of the variable. Remove the__autoreleasing
and a default mode will be assumed, and in this case I'd suggest being explicit is certainly good.The autoreleasing mode means the variable contains a reference which is not owned, reads should retain if necessary and writes can just write. It is used mainly for variables passed by reference.
You might notice that in the example above the variable
myError
has mode strong (implicitly) and yet it is passed by reference as autoreleasing - the compiler handles this automatically by introducing a temporary autoreleasing variable, copying without retaining the current reference inmyError
into it, and passing the temporary by reference as the argument toexecute:
. After the call returns the compiler does a normal assignment from the temporary tomyError
, which results in any old reference being released and the returned one retained.For more details see Apple's Transitioning to ARC Release Notes
Followup to Comments
Q: Is
__autoreleasing
implicitly set?A: Well Apple's document is not specific, but the Clang documentation says it is implicit for indirect parameters. As above I'd recommend being explicit, clarity is a Good Thing™.
Q: Does the placement matter?
A: Yes, and no... This is a C declaration, the stuff of quiz questions ("What does the following declare..."). The qualifier should be between the two asterisks as it is a pointer to a (variable of type) autoreleasing pointer to an object, but Apple state the compiler is "forgiving" without being specific of what it forgives. Play it safe, put it in the right place.
Q: Should you not test for
error
beingNULL
before doing the indirect assignment?A: Of course you should, somewhere before you do the indirection. The code shown is just an outline and such detail was elided and covered by the
...
’s. However as it has been raised a few times over the years maybe I elided too much, a suitableif
has been added.