I'm trying to complete the puzzle.
__strong
is the default for all Objective-C retainable object pointers like NSObject, NSString, etc.. It's a strong reference. ARC balances it with a -release
at the end of the scope.
__unsafe_unretained
equals the old way. It's used for a weak pointer without retaining the retainable object.
__weak
is like __unsafe_unretained
except that it's an auto-zeroing weak reference meaning that the pointer will be set to nil as soon as the referenced object is deallocated. This eliminates the danger of dangling pointers and EXC_BAD_ACCESS errors.
But what exactly is __autoreleasing
good for? I'm having a hard time finding practical examples on when I need to use this qualifier. I believe it's only for functions and methods which expect a pointer-pointer such as:
- (BOOL)save:(NSError**);
or
NSError *error = nil;
[database save:&error];
which under ARC has to be declared this way:
- (BOOL)save:(NSError* __autoreleasing *);
But this is too vague and I'd like to fully understand why. The code snippets I find place the __autoreleasing inbetween the two stars, which looks weird to me. The type is NSError**
(a pointer-pointer to NSError), so why place __autoreleasing
inbetween the stars and not simply in front of NSError**
?
Also, there might be other situations in which I must rely on __autoreleasing
.
You're right. As the official documentation explains:
All of this is very well explained in the ARC transition guide.
In your NSError example, the declaration means
__strong
, implicitly:Will be transformed to:
When you call your
save
method:The compiler will then have to create a temporary variable, set at
__autoreleasing
. So:Will be transformed to:
You may avoid this by declaring the error object as
__autoreleasing
, directly.Following up on Macmade's answer and Proud Member's follow up question in the comments, (would have also posted this as a comment but it exceeds the max character count):
Here is why the variable qualifier of __autoreleasing is placed between the two stars.
To preface, the correct syntax for declaring an object pointer with a qualifier is:
The compiler will forgive this:
but it isn't correct. See the Apple ARC transition guide (read the section that begins "You should decorate variables correctly...").
To address to the question at hand: A double pointer cannot have an ARC memory management qualifier because a pointer that points to a memory address is a pointer to a primitive type, not a pointer to an object. However, when you declare a double pointer, ARC does want to know what the memory management rules are for the second pointer. That's why double pointer variables are specified as:
So in the case of a method argument that is a double NSError pointer, the data type is declared as:
which in English says "pointer to an __autoreleasing NSError object pointer".
The definitive ARC specification says that
So for example, the code
actually gets converted to
... which is why it works when you have a parameter
NSError* __autoreleasing * errorPointer
, the called method will then assign the error to*errorPointer
and the above semantics will kick in.You could use
__autoreleasing
in a different context to force an ARC object into the autorelease pool, but that's not terribly useful since ARC only seems to use the autorelease pool at method return and already handles that automatically.