Ale*_*lex 3 cocoa objective-c objective-c-blocks automatic-ref-counting
我想了解为什么这会因EXC_BAD_ACCESS错误而崩溃.它从方法调用返回正常,但之后立即崩溃[self runMethodThatAssignsError:&error].
我在这里找到了类似的帖子,但它没有解释发生了什么,而且相当陈旧.
- (void)checkError {
NSError *error;
[self runMethodThatAssignsError:&error]; // crashes after returning
NSLog(@"success");
}
- (BOOL)runMethodThatAssignsError:(NSError **)error {
[@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
*error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
}];
return NO;
}
Run Code Online (Sandbox Code Playgroud)
在Instruments中运行示例代码,似乎-[NSArray enumerateObjectsUsingBlock:]将其块包装在自动释放池中.由于NSError **指针是,默认情况下,隐含地假定__autoreleasing,你NSError当它被分配给对象会被自动释放*error,因此通过收获-[NSArray enumerateObjectsUsingBlock:]的自动释放池.
有两种方法可以解决这个问题.第一个是在块之外使用局部变量,以使ARC保留它直到枚举完成后:
- (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;
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以将error参数声明为__strong,这将阻止首先将NSError其放入自动释放池中.请注意,只有在此方法的客户端始终使用ARC时才应该这样做,因为否则它可能会导致错误泄漏,因为客户端不希望发布它们,因为这种方法是非常规的.
- (BOOL)runMethodThatAssignsError:(NSError * __strong *)error {
[@[@1] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if (error) *error = [NSError errorWithDomain:@"1" code:7 userInfo:@{}];
}];
return NO;
}
Run Code Online (Sandbox Code Playgroud)