I noticed this pattern in Apple functions which return errors
error:(NSError *__autoreleasing *)outError
I understand the meaning, that it's pointer to pointer, used to carry out the result (using just * would change only the local copied variable, but not the outside one) but I'm concerned about the:
__autoreleasing
What happens if I leave it out? Do I get a leak? Why is it necessary?
You don't have to explicitly specify __autoreleasing when defining a function that
returns an object, for example
-(BOOL)doSomething:(NSError **)error;
The ARC compiler automatically inserts the __autoreleasing. This is explained in
the Clang/ARC documentation:
4.4.2 Indirect parameters
If a function or method parameter has type T*, where T is an
ownership-unqualified retainable object pointer type, then:
if T is const-qualified or Class, then it is implicitly qualified with
__unsafe_unretained;
otherwise, it is implicitly qualified with __autoreleasing.
The Xcode code completion
also knows about that and displays (NSError *__autoreleasing *)error.
When calling such a function the ARC compiler also automatically does
"the right thing", so you can just call
NSError *error;
BOOL success = [self doSomething:&error];
As explained in the "Transitioning to ARC Release Notes", the compiler inserts a temporary
__autoreleasing variable:
NSError *error;
NSError * __autoreleasing tmp = error;
BOOL success = [self doSomething:&tmp];
error = tmp;
(For the gory details you can read 4.3.4 "Passing to an out parameter by writeback" in
the Clang/ARC documentation.)
Related
Since in projects with automatic reference counting NSString * aString; means implicitly NSString * __strong aString;. Does it also count for the parameters and return types?
Is
- (NSString *)doubleString:(NSString *)aString {
return [NSString stringWithFormat:#"%#%#", aString, aString];
}
the same compiled code as
- (NSString * __strong)doubleString:(NSString * __strong)aString {
return [NSString stringWithFormat:#"%#%#", aString, aString];
}
and in every similar method?
Short answer: Yes. Both variants produce the same compiled code, as can be verified
by "Product -> Perform Action... -> Assemble ..." from the Xcode menu.
Longer answer: (The following references and citations are from the Clang/ARC documentation.)
Your question about the return value. According to
"4 Ownership qualification",
qualifiers like __strong and __weak apply to locations in memory where a pointer
to an object is stored, and they specify the semantics when loading from or storing to
an lvalue (4.2 Semantics).
The return value of a method is not such a location in memory (it is not an lvalue),
therefore the concept of ownership qualification does not apply here.
It makes not differences if the method is declared as returning (NSString * __weak) or (NSString * __strong), there is no difference in the compiled code.
A slightly different question is whether the caller owns the
returned object (it has a +1 retain count) or not. This depends by default on the method name, as explained in "3.2.2 Retained return values"
and "3.2.3 Unretained return values".
Your question about the parameters. Declaring the parameter as
(NSString * __strong) is identical to (NSString *). This can already be seen
from the Xcode autocompletion (where the "__strong" qualifier is not shown), but
also from the generated Assembly code.
This does not mean that arguments are retained when calling a method.
By default, they are not, as explained in
"3.2 Retainable object pointers as operands and arguments".
If an parameter is declared as __weak, it seems (from the Assembly code) that a temporary weak reference is created in the method, i.e.
- (NSString *) doubleString:(NSString * __weak)aString {
return [NSString stringWithFormat:#"%#%#", aString, aString];
}
is essentially the same as
- (NSString *) doubleString:(NSString *)aString {
NSString *__weak wString = aString;
return [NSString stringWithFormat:#"%#%#", wString, wString];
}
But I was not able to find a definite reference for this.
I have an NSError ** stored in an array (so I can get it as such array[0]). I'm trying to cast it into a variable:
NSError * __autoreleasing *errorPointer = (NSError * __autoreleasing *)array[0];
so I can access the underlying object as *errorPointer.
However, Xcode complains that Cast of an Objective-C pointer to 'NSError *__autoreleasing *' is disallowed with ARC. Is there any way to get to this object without turning off ARC?
Neither that stub:withBlock: method or any of its supporting infrastructure could be simply stuffing a double pointer into an NSArray. The array won't take non-objects, and a pointer to an object is not an object. There's something else going on.
This obviously requires some digging into the code to figure out. Where does the value get put into the array? That's in -[KWStub processInvocation:], and it's done apparently using a method added to NSInvocation by OCMock, getArgumentAtIndexAsObject:. In that method, the invocation uses a switch to check the type of the argument that is requested, and boxes it up if necessary.
The relevant case here is the last one, where the argument type is ^, meaning "pointer". This sort of argument is wrapped up in an NSValue; therefore, the array recieved by your Block actually contains, not the double pointer itself, but an NSValue representing the outer pointer. You just need to unbox it.
That should look like this:
NSValue * errVal = array[1];
NSError * __autoreleasing * errPtr = (NSError * __autoreleasing *)[errVal pointerValue];
As per Transitioning to ARC Release Notes:
__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.
For example:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
But what are the advantages of the above comparing to:
-(BOOL)performOperationWithError:(NSError * __strong *)error;
Update:
Several answers refer to the temp var trick compiler does to deal with the mismatch between var and argument as the advantage of __autoreleasing. I don't see why compiler can not do the same trick for __strong argument. I mean, for a __weak var and __strong argument, compiler can similarly do this:
NSError * __weak error;
NSError * __strong tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {
// Report the error.
}
Compiler knows -(BOOL)performOperationWithError:(NSError * __strong *)error; returns a strong reference(+1) so it handles it just like any new-family method. Since tmp lives in the same scope as error, compiler can reasonably keep it alive as long as error so the __weak reference(error) is now supported by a __strong reference(tmp) and will not be nullified until the end of the scope.
tl;dr
Implicitly converting a __weak object to a __strong object in this case would alter the semantic of the program, something that a compiler should never do.
The scenario
Let's take an example
NSError *error;
BOOL success = [myObject performOperationWithError:&error];
if (!success) {
// Report the error
}
In such a case the error local variable is automatically inferred by ARC as __strong.
At the same time the error argument of
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
is of type NSError * __autoreleasing *.
Please note that in any case ARC will infer parameters passed by reference (id *) as being of type id __autoreleasing *, so the above signature is equivalent to
-(BOOL)performOperationWithError:(NSError **)error;
under ARC.
Therefore we have a mismatch since we are passing a __strong annotated variable to a method expecting an __autoreleasing argument.
Under the hood
In our example then the compiler will address such mismatch by creating a local __autoreleasing tmp variable.
The code becomes
NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL success = [myObject performOperationWithError:&tmp];
error = tmp;
if (!success) {
// Report the error.
}
An alternative
Let's now pretend that we can change the signature of performOperationWithError:.
If we want to avoid the "compiler trick" which uses the tmp variable, we can declare our signature as
-(BOOL)performOperationWithError:(NSError * __strong *)error;
We have a __strong variable and we are now passing it to a method expecting a __strong argument, so we just eliminated the mismatch.
Looks good, why not always declare __strong arguments?
One reason is that declaring the argument as __autoreleasing will make the method to accept even a __weak reference.
It does not make much sense in the current example, but there could be cases in which we'd like to pass a __weak variable by reference and declaring __autoreleasing (or leaving the ARC to infer it) will allow us to do so.
ARC will apply the same trick seen above, creating a __autoreleasing tmp variable.
Conclusion
The mechanism presented so far goes under the name of pass-by-writeback.
Such mechanism has been designed to work with __autoreleasing, __strong and __weak variables, so that the programmer can safely rely on the type inference made by the compiler and not care too much about annotating variables around.
Declaring a id __strong * argument may make sense in some cases, but in general it could lead to unexpected errors generated by the compiler.
My advice here is: "let the compiler do his magic and you'll be good"
Update
I don't see why compiler can not do the same trick for __strong argument.
Telling the compiler to handle in an __autoreleasing fashion the management of either a __strong or __weak variable it's ok since it basically means: "Please, compiler, do the right thing automatically".
That's why the trick seen above will work without issues.
On the other hand, if you declare a variable as __weak you presumably have a good reason for doing so and the last thing you want is to have it implicitly retained when you clearly specified otherwise. That would radically change the semantic of the piece of code you've written, therefore the compiler won't do that (thank God!).
In other words
__weak --> __autoreleasing good
__strong --> __autoreleasing good
__weak <--> __strong wrong!
The only advantage is, as you said, that the object is autoreleased on return. So without ARC it's the same as sending retain and autorelease. In C every variable passed as argument is copied, so this doesn't influence what will be done with the original pointer, but just with the copied pointer.
An example of advantage could be this, let's say the argument isn't __autoreleasing:
-(BOOL)performOperationWithError:(NSError * __strong *)error;
So I call the method passing a weak reference:
NSError* __weak error;
[object performSelectorWithError: &error];
What happens here? The copied argument isn't autoreleased on return, so when the method returns error is nil. If instead the method was this one:
-(BOOL)performOperationWithError:(NSError * __autoreleasing *)error;
This case the error had still a retain count of 1, but it was autoreleased, so it wasn't nil and could have been used inside the pool.
The other reason which I haven't seen mentioned is to follow Cocoa conventions so that ARC code can properly interoperate with non-ARC code.
Under ARC, an out-parameter takes the following form (by default; this is equivalent to NSError **):
- (BOOL)tryWithError:(NSError *__autoreleasing *)err;
From the Transitioning to ARC Release Notes, if we pass the address of a __strong local variable, the compiler will create a temporary variable and generate the following code:
NSError *error; // strong
BOOL ok = [myObject tryWithError:&error];
// translated to
NSError *__strong error;
NSError *__autoreleasing tmp = error;
BOOL ok = [myObject tryWithError:&tmp];
error = tmp;
But if we do it with an instance variable:
#implementation Foo {
NSError *_error; // strong
}
- (void)bar
{
[myObject tryWithError:&_error];
}
...
this gives us the error
Passing address of non-local object to __autoreleasing parameter for write-back.
Why is this invalid? Couldn't the compiler just translate such code automatically to this?
- (void)bar
{
NSError *__autoreleasing tmp = _error;
[myObject tryWithError:&tmp];
_error = tmp;
}
After all, this is what I will be writing anyway to solve the problem!
Note: adding the out keyword to the parameter type will reduce the compiler's work slightly because it doesn't have to read the current value into the temporary variable — but this doesn't take care of the error.
A pointer to an ivar can't be passed to an “id __autoreleasing *” argument under ARC because that kind of pass-by-writeback is ill-formed. The respective section in the ARC specification lists legal forms of pass-by-writeback, the only one applicable here is
&var, where var is a scalar variable of automatic storage duration
with retainable object
, so only automatic storage duration (a local variable) is allowed.
Why this is invalid: I am pretty sure the reason here is compatibility with older code:
1) You should only look at the error writeback in the failure case. In the success case, there is no guarantee at all what's inside the error pointer.
2) In general, whether the writeback value should be used or not depends on the contract of the method. That is something the compiler cannot check.
This is the version of the code that matches the type of &error (NSError * __autoreleasing *) to the type of the writeback (NSError ** which is interpreted as NSError * __autoreleasing *). If ok is YES, the error value won't be touched.
NSError * __autoreleasing error;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
// use error
}
However, those __autoreleasing are ugly, so instead of forcing us to use __autoreleasing all over the place, the compiler allows us to pass a __strong (but local) variable as well (default ownership):
NSError *error;
BOOL OK = [myObject performOperationWithError:&error];
if (!OK) {
// use error
}
According to the docs, that gets rewritten to:
NSError * __strong error;
NSError * __autoreleasing tmp = error;
BOOL OK = [myObject performOperationWithError:&tmp];
error = tmp;
if (!OK) {
// use error
}
Not a problem at all, the error will only be used in the success case.
Now let's have a look at a __strong instance variable _error. Why doesn't the compiler allow that? Here is what the rewrite would look like:
NSError * __autoreleasing tmp = _error;
BOOL OK = [myObject performOperationWithError:&tmp];
_error = tmp;
if (!OK) {
// use error
}
The problem here is that the writeback in tmp would always be used (assigned to the instance variable _error), ignoring the contract of the method that the writeback should only be used in error cases (or in general whatever the documentation of the method says). A safe way to assign the last error to an instance variable would be
NSError * __autoreleasing tmp = _error;
BOOL OK = [myObject performOperationWithError:&tmp];
if (!OK) {
_error = tmp;
// use error
} else {
_error = nil; // Make sure that _error is nil if there was no error.
}
And that's only true for the convention of Cocoa's methods which return an error. In general there is no way for the compiler to tell what a method will do with an id *: There may be old methods out there that use different conventions. So if you really want to store the writeback in a __strong instance variable, you currently have to walk the extra mile yourself, and I don't expect this to change.
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:
__autoreleasing to denote arguments that are passed by reference (id *) and are autoreleased on return.
All of this is very well explained in the ARC transition guide.
In your NSError example, the declaration means __strong, implicitly:
NSError * e = nil;
Will be transformed to:
NSError * __strong error = nil;
When you call your save method:
- ( BOOL )save: ( NSError * __autoreleasing * );
The compiler will then have to create a temporary variable, set at __autoreleasing. So:
NSError * error = nil;
[ database save: &error ];
Will be transformed to:
NSError * __strong error = nil;
NSError * __autoreleasing tmpError = error;
[ database save: &tmpError ];
error = tmpError;
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:
NSError * __qualifier someError;
The compiler will forgive this:
__qualifier NSError *someError;
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:
SomeClass * __qualifier *someVariable;
So in the case of a method argument that is a double NSError pointer, the data type is declared as:
- (BOOL)save:(NSError* __autoreleasing *)errorPointer;
which in English says "pointer to an __autoreleasing NSError object pointer".
The definitive ARC specification says that
For __autoreleasing objects, the new pointer is retained, autoreleased, and stored into the lvalue using primitive semantics.
So for example, the code
NSError* __autoreleasing error = someError;
actually gets converted to
NSError* error = [[someError retain] autorelease];
... 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.
To be short: this is only for compatibility with MRC.
Apple have made agreement that in own libraries objects returned by ** are always autoreleased. So ARC code will work fine with old binaries (for example if you have deployment target iOS 4) and vise versa MRC code will work fine with ARC binaries.
So in conclusion:
You should never use __autoreleasing: compiler will automatically add it where needed
If you are not going to support MRC code, then you should use * __strong * everywhere. It will save from crashes of family:
#autoreleasingpool {
*autorelesingOut = [#"crash maker" mutableCopy];//NSString * __autoreleasing *autorelesingOut;
*strongOut = [#"it's ok" mutableCopy];//NSString * __strong *strongOut;
//App will crash if autorelesingOut will be referenced outside of this autoreleasepool
}