Be careful when assigning values to out-parameters when Automatic Reference Counting. Ensure that there is no auto-release pool in-between where you assign the parameter and where you use the out-parameter. Easily overlooked when using C blocks, especially when passing blocks to Cocoa APIs which can enclose your handler within an auto-release pool without you realising it.
See example below. It represents the kind of situation not-uncommonly found within Cocoa software: a message argument passes an error by reference, a pointer to a pointer. Please note, the example is entirely fictional. The program below does nothing useful, except to demonstrate the principle.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
Under the Automatic Reference Counting using the LLVM compiler, the
outError argument implicitly adds
__autoreleasing to its type. In other words
NSError *__autoreleasing *
See indirect parameters for the rationale. This additional implicit qualifier implies that the
NSError pointer exists on the stack frame subject to release by an auto-release pool.
No problem so far.
Looking at line 19, you would never deliberately enclose the out-parameter assignment within an autorelease pool. The situation might arise however inadvertently when you attempt to do the same thing from within a completion handler block sent to one of Apple’s APIs, e.g. sending a synchronous URL requestor running a block with a Core Data context. The handler block makes the assignment but while unwinding the stack, a hidden auto-release pool deallocates and reclaims the error object leaving its auto-releasing pointer sitting on the enclosing stack frame dangling in space. When you attempt to access the error, you of course see
EXC_BAD_ACCESS; the error has disappeared.
So look out for that!
The solution is relatively straightforward. Temporarily assign the out-parameter’s value to an automatic (stack frame) variable with
__strong or no qualifier. No qualifier is the same as strong. Then just before returning, assign the out-parameter, e.g.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15