在块崩溃中分配 NSError 的调用方法
Call Method that assigns NSError in Block Crashes
我想了解为什么会因 EXC_BAD_ACCESS
错误而崩溃。它 returns 从方法调用正常,但随后在 [self runMethodThatAssignsError:&error]
上立即崩溃。
我有 found a similar post here,但它没有解释发生了什么,而且相当陈旧。
- (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;
}
运行 您在 Instruments 中的示例代码,似乎 -[NSArray enumerateObjectsUsingBlock:]
正在将其块包装在自动释放池中。由于 NSError **
指针在默认情况下被隐式假定为 __autoreleasing
,您的 NSError
对象在分配给 *error
时自动释放,因此被 [=12= 回收]的自动释放池。
有两种方法可以解决这个问题。第一个是在块外使用局部变量,使 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;
}
或者,您可以只将 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;
}
我想了解为什么会因 EXC_BAD_ACCESS
错误而崩溃。它 returns 从方法调用正常,但随后在 [self runMethodThatAssignsError:&error]
上立即崩溃。
我有 found a similar post here,但它没有解释发生了什么,而且相当陈旧。
- (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;
}
运行 您在 Instruments 中的示例代码,似乎 -[NSArray enumerateObjectsUsingBlock:]
正在将其块包装在自动释放池中。由于 NSError **
指针在默认情况下被隐式假定为 __autoreleasing
,您的 NSError
对象在分配给 *error
时自动释放,因此被 [=12= 回收]的自动释放池。
有两种方法可以解决这个问题。第一个是在块外使用局部变量,使 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;
}
或者,您可以只将 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;
}