I have a method like this:
- (void)processAThing:(id)thing error:(NSError * __autoreleasing *)error
{
@autoreleasepool {
// Start processing.
// Find some partway through error..
if (error) {
*error = [NSError errorWithDomain...];
return NO;
}
// More processing.
}
}
This is broken and crashes, because the NSError is autoreleased, and when the return happens, the pool is drained, so the thing that the caller gets is now bogus.
I know I could significantly redesign the method so I collect all error cases outside the autorelease block, but I want to understand whether there's a correct way of handling the error object in this situation. I can't alloc/init a speculative NSError outside the pool block, because the domain and code properties are readonly (and I still think the reference would disappear when the method returns).
It solves the problem if I change the method declaration to this:
- (void)processAThing:(id)thing error:(NSError * __strong *)error
But then I need to fuss around at the call site in a nonstandard way, and this seems egregious to make the caller pay the price for my internal autoreleasepool.
Any thoughts? Thanks.
I had this problem myself. In this case, I think you just need to declare a new strong reference just before the @autoreleasepool
, and set the method argument just after the @autoreleasepool
block from that temporary reference.
- (void)processAThing:(id)thing error:(NSError * __autoreleasing *)error {
__strong NSError *errOut = nil;
@autoreleasepool {
// do your stuff and set errOut instead of error
}
if (error) {
*error = errOut;
}
}
(typed in browser, not error checked by compiler)
As for your premature return, I guess you'll have to use a jump label (even if it's not pretty).