12

私はこのコードに取り組んでいます。これはネット上で長い非同期操作を実行し、終了すると完了ブロックをトリガーしてテストを実行し、変数が特定の値を取得した場合、別の長い操作をすぐに開始する必要があります。

-(void) performOperation
{

    void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request){


        int variable=0;

        // Do completion operation A
        //...
        //...

        // Do completion operation B                
        //Get the variable value

        if(variable>0){
            [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock];
        }

    };

//Perform the lenhgty operation with the above completionBlock
    [self doLengthyAsynchronousOperationWithCompletionBlock: completionBlock];

}

-(void) doLengthyAsynchronousOperationWithCompletionBlock: completionBlock
{
    //Do some lengthy asynchronous stuff
}

このコードを使用すると、コンパイラから次の警告が表示されます。

WARNING: Block pointer variable 'completionBlock' is uninitialized when caputerd by the block

私が変更され:

void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)

の:

__block void(^completionBlock) (id obj, NSError *err, NSURLRequest *request)= ^(id obj,NSError *err, NSURLRequest *request)

しかし、私はこの他の警告を受け取ります:

WARNING 2: Capturing 'completionBlock' strongly in this block is likely to lead to a retain cycle

どうすればこれを修正できますか?

ありがとう

ニコラ

4

1 に答える 1

29

警告:ブロックポインタ変数'completionBlock'は、ブロックによってキャプチャされたときに初期化されていません

これは、再帰ブロックに初期化されたブロック変数に__blockストレージが必要なために発生します。

  • ブロック内の変数は、で宣言されていない限りコピーされます。宣言さ__blockれている場合は、参照として渡されます。
  • 再帰ブロックがブロック変数に割り当てられると、割り当ての前に作成が行われ、そのような作成によって変数のコピーがトリガーされます。変数がまだ割り当てられていない場合、コピーされた変数は不正な値になり、ブロックが実行されるとクラッシュします。
  • ただし、を追加する__blockと、代わりに変数への参照を使用してブロックが作成されます。次に、変数が作成されたブロックに初期化され、ブロックを使用できるようになります。

警告:このブロックで「completionBlock」を強くキャプチャすると、保持サイクルが発生する可能性があります

これは、ブロック変数がブロックへの強力な参照であり、ブロック自体が変数を参照しているために発生します(前に見たように、変数にはが含まれている__blockため、コピーされる代わりに参照されます)。

だから私たちは必要です

  • ブロック内の強い変数への弱参照。
  • また、ブロックが作成されたメソッドのスコープ中にブロックが割り当て解除されるのを防ぐための外部の強力な参照。
    void(^ completeBlock)(id obj、NSError * err、NSURLRequest * request);
    void(^ __block __weak weakCompletionBlock)(id obj、NSError * err、NSURLRequest * request);
    weakCompletionBlock = completeBlock = ^(id obj、NSError * err、NSURLRequest * request){
        [self lengthyAsyncMethod:weakCompletionBlock];
    };

この名前doLengthyAsynchronousOperationWithCompletionBlockは、メソッドがブロックが作成されたメソッドスコープよりも長持ちする可能性があることを示しています。コンパイラが引数として渡されたブロックをコピーしない場合、このブロックをコピーするのはこのメソッドの責任です。このブロックをブロック対応コード(例:)で使用している場合dispatch_async()、これは自動的に行われます。

このブロックをインスタンス変数に割り当ててい@property(copy)た場合、ブロック内のselfへの弱参照とが必要になりますが、そうではないため、selfを使用します。

于 2013-03-26T14:19:02.467 に答える