Setting NSError within a block, using ARC
Note: As of 2020, this workaround is no longer necessary.
Try this:
// ...__block NSError *blockError = nil;[items enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) { NSError *localError = nil; if (![blockSelf doSomethingWithItem:item error:&localError]) { blockError = localError; }}];// ...
As for exactly why this is necessary, I'm still trying to get a grasp on that myself. I'll update this answer when I do. :)
What is the correct way to set an NSError from within a block?
As seen on "What's new in LLVM?" @ 14:55, there are two techniques to address the issue with the NSError which is implicitly autoreleasing.
Easiest fix is to use __strong
- (BOOL)frobnicateReturningError:(NSError *__strong *)error{ NSArray *items = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil]; __block Frobnicator *blockSelf = self; [items enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) { NSError *innerError = nil; [blockSelf doSomethingWithItem:item error:&innerError]; if(innerError && error) { *error = [NSError errorWithDomain:...]; } }];}
Second fix is to use __block
- (BOOL)frobnicateReturningError:(NSError **)error{ NSArray *items = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil]; __block Frobnicator *blockSelf = self; __block NSError *strongError = nil; [items enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) { NSError *innerError = nil; [blockSelf doSomethingWithItem:item error:&innerError]; if(innerError) { strongError = [NSError errorWithDomain:...]; } }]; if (error) *error = strongError; }