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];
    }];
}

これはコンパイルされますが、変更するブロックのローカルNSErrorを作成しようとすると、変更される可能性があります。これは、列挙後に元のNSErrorを設定するために使用されerrorます (これは表示していません)。doSomethingWithItemerror

- (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ソースコード自体からの結果のみが返されます。

動作しているように見えますが、少し醜い解決策の1つは、内部および外部のエラーポインタを用意することです。

- (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 を設定する正しい方法は何ですか?

「 What's new in LLVM? 」@ 14:55 で見られるように、暗黙的に自動解放される NSError の問題に対処する 2 つの手法があります。

最も簡単な修正は __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:...];
        }
    }];
}

2番目の修正は__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 に答える