11

我希望使用自动引用计数从项目的块中设置一个 NSError 指针。以下是我的代码的简化版本:

- (BOOL)frobnicateReturningError:(NSError **)error
{
    NSArray *items = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];

    __block Frobnicator *blockSelf = self;
    [items enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) {
        [blockSelf doSomethingWithItem:item error:error];
    }];
}

这可以编译,但error可以通过 doSomethingWithItem我尝试为要修改的块创建一个本地 NSError 来修改,然后error在枚举之后使用它来设置原始值(我没有显示):

- (BOOL)frobnicateReturningError:(NSError **)error
{
    NSArray *items = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];

    __block Frobnicator *blockSelf = self;
    __block NSError *blockError = nil;
    [items enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) {
        [blockSelf doSomethingWithItem:item error:&blockError];
    }];
}

这无法编译并出现以下错误:

将非本地对象的地址传递给 __autoreleasing 参数以进行回写

谷歌搜索这个错误只会返回 Clang 源代码本身的结果。

一种似乎可行但有点难看的解决方案是拥有一个内部和外部错误指针:

- (BOOL)frobnicateReturningError:(NSError **)error
{
    NSArray *items = [NSArray arrayWithObjects:@"One", @"Two", @"Three", nil];

    __block Frobnicator *blockSelf = self;
    __block NSError *outerError = nil;
    [items enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) {
        NSError *innerError = nil;
        [blockSelf doSomethingWithItem:item error:&innerError];
        outerError = innerError;
    }];
}

从块中设置 NSError 的正确方法是什么?

4

2 回答 2

9

注意:自 2020 年起,不再需要此解决方法。


试试这个:

// ...
__block NSError *blockError = nil;
[items enumerateObjectsUsingBlock:^(id item, NSUInteger idx, BOOL *stop) {
    NSError *localError = nil;
    if (![blockSelf doSomethingWithItem:item error:&localError]) {
        blockError = localError;
    }
}];
// ...

至于为什么这是必要的,我仍在尝试自己掌握这一点。当我这样做时,我会更新这个答案。:)

于 2011-08-02T05:56:10.067 回答
1

从块中设置 NSError 的正确方法是什么?

正如在“ LLVM 中有什么新功能? ”@ 14:55 中所见,有两种技术可以解决隐式自动释放的 NSError 问题。

最简单的解决方法是使用 __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:...];
        }
    }];
}

第二个修复是使用 __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;
    }
于 2017-10-06T15:34:11.880 回答