Setting NSError within a block, using ARC Setting NSError within a block, using ARC objective-c objective-c

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;    }