1

Objective-C で ARC を使用しているときに、いつブロックをコピーする必要があるかについて、矛盾する情報を取得しています。アドバイスは「常に」から「決して」までさまざまなので、どうすればよいかわかりません。

たまたま、説明の仕方がわからないケースがあります。

-(RemoverBlock)whenSettledDo:(SettledHandlerBlock)settledHandler {
    // without this local assignment of the argument, one of the tests fails. Why?
    SettledHandler handlerFixed = settledHandler;

    [removableSettledHandlers addObject:handlerFixed];

    return ^{
        [removableSettledHandlers removeObject:handlerFixed];
    };
}

これは、次のようなインライン ブロックで呼び出されます。

-(void) whatever {
    [self whenSettledDo:^(...){
        ...
    }];
}

(このスニッパーが適用された実際のコードはこちらです。)

ここで引数をローカル変数にコピーすると何が変わるでしょうか? addObject 用と removeObject 用の 2 つの異なるコピーを作成するローカルのないバージョンなので、削除されたコピーは追加されたコピーと一致しませんか?

ARC がブロックを正しく処理しないのはなぜですか? それは何を保証し、私の責任は何ですか?これらすべてが曖昧でない方法で文書化されているのはどこですか?

4

3 に答える 3

0

私の特定の問題が、実際にはブロックの 2 つの異なるコピーを作成していたことを確認しました。トリッキートリッキー。これは、適切なアドバイスが「ブロックをそれ自体と比較できるようにしたい場合を除き、コピーしないでください」であることを意味します。

テストに使用したコードは次のとおりです。

-(void) testMultipleCopyShenanigans {
    NSMutableArray* blocks = [NSMutableArray array];
    NSObject* v = nil;
    TOCCancelHandler remover = [self addAndReturnRemoverFor:^{ [v description]; } 
                                                         to:blocks];
    test(blocks.count == 1);
    remover();
    test(blocks.count == 0); // <--- this test fails
}
-(void(^)(void))addAndReturnRemoverFor:(void(^)(void))block to:(NSMutableArray*)array {
    NSLog(@"Argument: %@", block);
    [array addObject:block];
    NSLog(@"Added___: %@", array.lastObject);
    return ^{
        NSLog(@"Removing: %@", block);
        [array removeObject:block];
    };
}

このテストを実行したときのログ出力は次のとおりです。

Argument: <__NSStackBlock__: 0xbffff220>
Added___: <__NSMallocBlock__: 0x2e283d0>
Removing: <__NSMallocBlock__: 0x2e27ed0>

引数は、スタックに格納されている NSStackBlock です。配列またはクロージャに配置するには、ヒープにコピーする必要があります。ただし、これは配列への追加とクロージャーの両方で 1 回発生します。

したがって、配列内の NSMallocBlock のアドレスは 83d0 で終わりますが、配列から削除されたクロージャのアドレスは 7ed0 で終わります。それらは異なります。一方を削除しても、もう一方を削除したことにはなりません。

うーん、今後気をつけないといけないですね。

于 2013-10-16T01:00:51.683 に答える