In Apple's documentation about ARC, they make a point of spelling out a problematic scenario in which ARC will generate a boilerplate temporary variable behind the scenes. Search on "The compiler therefore rewrites":
https://developer.apple.com/library/mac/releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html
The gist of the warning seems to be that because the stack-based variable is "strong" and the by-reference parameter to the called method (performOperationWithError:) is autoreleasing, ARC will generate a temporary local variable to serve the memory management needs of the autoreleasing variable. But because the temporary variable is assigned to the strong variable in the boilerplate example, it seems as though from a client's point of view there is no risk.
What exactly is the documentation taking pains to warn us about here? What is the risk as either a client or as an implementor of a method that may be called in this way (with an autoreleased, return-by-value parameter)?
It's only a warning about less than ideal performance. In the rewritten code, the NSError pointed to by "tmp" comes back autoreleased, is retained when assigned to "error", and then is released again when "error" goes out of scope.
If you change the declaration in the original code to: NSError __autoreleasing *error;
If you do this, there is no assignment to a temp, and that implicit retain and then release no longer occurs. (The NSError object itself is still valid for exactly as long as it was before, since it is still in the autorelease pool.) So the documentation is warning you that if you use the "wrong" variable qualifier that it can cause extra retain count munging that wouldn't otherwise be required.
Also note that with either version of the code: Because the variable in question is passed by reference and isn't the return value from -performOperationWithError:, there isn't the opportunity to do the magic stack walking trick that ARC can do to save the object from going into the autorelease pool in the first place.
I think it’s to prevent confusion if you start looking at the values passed into the method. In their example, if I set a breakpoint on the line that calls [myObject performOperationWithError:&tmp];
and type p error
, I’ll see the address of it. But if I step into -performOperationWithError:
and type p error
, I’ll get a different value—inside the method, error
points to that temporary value.
I can see a situation where some poor sap is trying to debug something tricky with ARC where the pointer changing as it gets passed into the method would be an extremely confusing red herring.
My guess: If you made assumptions about the memory referenced by the output parameter, e.g indexing off the pointer, you might be surprised.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With