Running your example code in Instruments, it appears that -[NSArray enumerateObjectsUsingBlock:] is wrapping its block in an autorelease pool. Since NSError ** pointers are, by default, implicitly assumed to be __autoreleasing, your NSError object is autoreleased when it is assigned to *error, and consequently reaped by -[NSArray enumerateObjectsUsingBlock:]'s autorelease pool.
There are two ways to fix this. The first one is to use a local variable outside of the block, to cause ARC to retain it until after the enumeration has finished:
- (BOOL)runMethodThatAssignsError:(NSError **)error {
__block NSError *_error = nil;
[@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
_error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
}];
if (error) *error = _error;
return NO;
}
Alternatively, you can just declare the error parameter as __strong, which will prevent the NSError from being put in the autorelease pool in the first place. Note that this should only be done if the clients of this method are always going to be using ARC, because otherwise it will probably cause the errors to leak as the clients will not expect to have to release them, due to this approach being unconventional.
- (BOOL)runMethodThatAssignsError:(NSError * __strong *)error {
[@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (error) *error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
}];
return NO;
}
__block NSError *blockError = nil; [@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { blockError = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];}]; if (blockError) *error = blockError; return N0;?*error = ...without first making sure thaterrorisn'tnil. Never dereference a nil pointer.NSUInteger value = 0;before theenumerateObjectsUsingBlock:and then a try to set its value inside the block, the compiler should warn you (compile error or warning) asking for a__block. So I'd say it's the same here.NSError **pointer should be forNULL, notnil.nilis supposed to be used for object pointers (i.e.NSError *), not pointers to object pointers, although in practice they both have the same value.