Objective c 在块崩溃中分配NSError的调用方法

Objective c 在块崩溃中分配NSError的调用方法,objective-c,cocoa,automatic-ref-counting,objective-c-blocks,Objective C,Cocoa,Automatic Ref Counting,Objective C Blocks,我想了解为什么这会导致EXC\u BAD\u ACCESS错误而崩溃。它从方法调用返回,但随后在[self-runmethodthatsassignserror:&error]上立即崩溃 我知道,但它不能解释发生了什么,而且已经很老了 - (void)checkError { NSError *error; [self runMethodThatAssignsError:&error]; // crashes after returning NSLog(@"suc

我想了解为什么这会导致
EXC\u BAD\u ACCESS
错误而崩溃。它从方法调用返回,但随后在
[self-runmethodthatsassignserror:&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;
}

在Instruments中运行示例代码时,似乎
-[NSArray EnumerateObjectsSusingBlock:
正在自动释放池中包装其块。由于默认情况下,
NSError**
指针被隐式假定为
\uu自动删除
,因此
NSError
对象在分配给
*error
时会自动删除,并因此被
-[NSArray enumerateobjects susingblock:
的自动删除池获取

有两种方法可以解决这个问题。第一种方法是在块外使用局部变量,使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
参数声明为
\uu 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;
}

\uuu block n错误*blockError=nil;[@[@1]enumerateObjectsUsingBlock:^(id-obj,NSUInteger-idx,BOOL*stop){blockError=[nSErrorWithDomain:@“1”代码:7用户信息:@{};}];if(blockError)*error=blockError;返回N0?@Larme是的,这是个问题,这总是必需的吗?没办法吗?如果是这样的话,为什么?仅供参考-在事先确保
错误
不是
零之前,切勿执行
*错误=…
。永远不要取消对nil指针的引用
enumerateObjectsUsingBlock:
之前,然后尝试在块内设置其值,编译器应警告您(编译错误或警告)请求
\u块
。所以我想说这里也是一样。@rmaddy从技术上讲,对
NSError**
指针的检查应该是
NULL
,而不是
nil
nil
应该用于对象指针(即
NSError*
),而不是指向对象指针的指针,尽管实际上它们都具有相同的值。我推荐第一种方法。使用
NSError*\uu strong*
是非常不传统的。显然,这是有记录的,
块内分配的值将在执行块后被释放。使用retain显式维护这些值。
-