28

ARC を使用して、4.0 および 5.0 を対象とする iOS プロジェクトに取り組んでいます。

ブロック、ARC、およびブロック外からのオブジェクトの参照に関連する問題に遭遇しました。ここにいくつかのコードがあります:

 __block AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
   [operation setCompletionBlock:^ {
       if ([operation isCancelled]) {
           return;
       }

... do stuff ...

operation = nil;
}];

この場合、コンパイラは、ブロックで「操作」を使用すると保持サイクルが発生するという警告を出します。ARC では、__block が変数を保持するようになりました。

__unsafe_unretained を追加すると、コンパイラはオブジェクトをすぐに解放するため、明らかに機能しません。

4.0 をターゲットにしているので、__weak は使用できません。

私はこのようなことをしてみました:

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
__block __unsafe_unretained AFHTTPRequestOperation *weakOperation = operation;

ただし、weakOperation は nil ではありませんが、ブロック内にある場合、そのプロパティはどれも設定されません。

上記のプロジェクトの制約を考慮して、この状況を処理する最善の方法は何ですか?

4

2 に答える 2

23

進行が保証されていると仮定すると、保持サイクルはまさにあなたが望むものかもしれません。ブロックの最後で保持サイクルを明示的に中断するため、永続的な保持サイクルではありません。ブロックが呼び出されると、サイクルが中断されます。

ただし、操作を維持する何かがある場合は、__weakまたは__unsafe_unretained変数に参照を格納し、ブロック内からそれを使用できます。__blockなんらかの理由でブロック中に変数のバインディングを変更する必要がない限り、変数を修飾する必要はありません。もう中断する保持サイクルがないため、weak 変数に何も割り当てる必要はありません。

于 2011-10-13T22:42:38.757 に答える
1

これは Conrad Stoll がBlocks, Operations, and Retain Cyclesで説明した問題のようですが、彼の記事にはいくつかの重要な点が欠けています。

  • __blockMRC モードでキャプチャされた変数への強い参照を回避する Apple 推奨の方法のように見えますが、ARC モードでは完全に不要です。この場合、ARC モードではまったく不要です。MRC モードでも必要ありませんが、軽量の回避策ははるかに冗長です。void * unretainedOperation = operation; ... ^{ AFHTTPRequestOperation * op = unretainedOperation; }
  • ARC モードでは、強い参照 (キューに追加できるようにするため) と弱い/unsafe_unretained 参照の両方が必要です。

最も簡単な解決策は次のようになります。

AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
AFHTTPRequestOperation * __unsafe_unretained unretainedOperation = operation;

[operation setCompletionBlock:^ {
  if ([unretainedOperation isCancelled]) {
    return;
  }
  ... do stuff ...
}];

参照サイクルを中断したとしても、そもそもブロックが保持する理由はありませんAFHTTPRequestOperation(完了ハンドラーが完了するまで操作が存続すると仮定すると、これは常に保証されるわけではありませんが、通常は true であり、次の場合に ARC によって想定されます。self呼び出しスタックのさらに上を使用して参照されます)。

最善の修正は、操作を引数としてブロックに渡す最新の AFNetworkingに更新することです。

于 2013-06-03T16:31:57.327 に答える