しばらくの間ブロックを使用してきましたが、ARC 環境と非 ARC 環境の両方でメモリ管理について見逃していることがあると感じています。より深く理解することで、多くのメモリ リークを回避できると思います。
AFNetworking は、特定のアプリケーションでのブロックの主な用途です。ほとんどの場合、操作の完了ハンドラー内で、「[self.myArray addObject]」のようなことを行います。
ARC と非 ARC が有効な環境の両方で、Apple のこの記事に従って「自己」が保持されます。
つまり、AFNetworking ネットワーク操作の完了ブロックが呼び出されるたびに、self はそのブロック内に保持され、そのブロックが範囲外になると解放されます。これは、ARC と非 ARC の両方に当てはまると思います。Leaks ツールと Static Analyzer の両方を実行して、メモリ リークを見つけられるようにしました。どれも何も示しませんでした。
しかし、理解できない警告に出くわしたのはつい最近のことでした。この特定の例では ARC を使用しています。
ネットワーク操作の完了と失敗を示す 2 つのインスタンス変数があります
@property (nonatomic, readwrite, copy) SFCompletionBlock completionBlock;
@property (nonatomic, readwrite, copy) SFFailureBlock failureBlock;
@synthesize failureBlock = _failureBlock;
@synthesize operation = _operation;
コードのどこかで、私はこれを行います:
[self.operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id
responseObject) {
NSError *error = [NSError errorWithDomain:@"com.test" code:100 userInfo:@{@"description": @"zero results"}];
_failureBlock(error);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"nothing");
}];
Xcode は、failureBlock を呼び出す行について、「このブロックで "自己" を強力にキャプチャすると、保持サイクルが発生する可能性が高い」というメッセージとともに不平を言います。私は Xcode が正しいと信じています。そのため、2 つのブロックのいずれも割り当てが解除されません。
ただし、次の質問/観察があります。
1) _failureBlock(error) を "self.failureBlock(error)" (引用符なし) に変更すると、コンパイラは文句を言うのをやめます。何故ですか?これは、コンパイラが見逃しているメモリ リークですか?
2) 一般に、インスタンス変数であるブロックを使用する場合、ARC と非 ARC が有効な環境の両方でブロックを操作するためのベスト プラクティスは何ですか? AFNetworking の完了ブロックと失敗ブロックの場合、これら 2 つのブロックはインスタンス変数ではないため、上記で説明した保持サイクルのカテゴリにはおそらく該当しないようです。しかし、プログレス ブロックを AFNetworking に使用する場合、上記のような保持サイクルを回避するにはどうすればよいでしょうか?
ARC および非 ARC に関するブロックとメモリ管理の問題/解決策について、他の人の意見を聞きたいです。これらの状況はエラーが発生しやすいと感じており、問題を解決するためにこれについて議論する必要があると感じています。
問題があるかどうかはわかりませんが、最新の LLVM で Xcode 4.4 を使用しています。