142

ARC 対応のコードで、ブロックベースの API を使用している場合、保持サイクルの可能性に関する警告を修正する方法は?

警告:
Capturing 'request' strongly in this block is likely to lead to a retain cycle

このコード スニペットによって生成されます。

ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.rawResponseData error:nil];
    // ...
    }];

警告はrequest、ブロック内のオブジェクトの使用にリンクされています。

4

7 に答える 7

167

自分への返信:

ドキュメントの私の理解では、キーワードをblock使用し、ブロック内で使用した後に変数を nil に設定しても問題ないはずですが、それでも警告が表示されます。

__block ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil];
    request = nil;
// ....

    }];

更新: ' _block'の代わりにキーワード' _weak' を使用し、一時変数を使用して動作するようにしました:

ASIHTTPRequest *_request = [[ASIHTTPRequest alloc] initWithURL:...
__weak ASIHTTPRequest *request = _request;

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil];
    // ...
    }];

iOS 4 もターゲットにする場合は、__unsafe_unretained代わりに を使用し__weakます。同じ動作ですが、オブジェクトが破棄されたときにポインターが自動的に nil に設定されるのではなく、ぶら下がったままになります。

于 2011-08-26T13:24:07.073 に答える
50

この問題は、リクエストへの強い参照を持つブロックをリクエストに割り当てているために発生します。ブロックは自動的にリクエストを保持するため、サイクルのために元のリクエストが解放されることはありません。わかる?

__block でリクエストオブジェクトにタグを付けて、それ自体を参照できるようにしているので、それは奇妙です。に弱い参照を作成することで、これを修正できます。

ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...];
__weak ASIHTTPRequest *wrequest = request;

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil];
    // ...
    }];
于 2013-01-07T15:00:48.940 に答える
14

ブロック内に自己を保持していることが原因です。ブロックは自己からアクセスされ、自己はブロック内で参照されます。これにより、保持サイクルが作成されます。

の弱い参照を作成して、これを解決してみてくださいself

__weak typeof(self) weakSelf = self;

operationManager = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
[operationManager setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

    [weakSelf requestFinishWithSucessResponseObject:responseObject withAFHTTPRequestOperation:operation andRequestType:eRequestType];

} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    [weakSelf requestFinishWithFailureResponseObject:error withAFHTTPRequestOperation:operation andRequestType:eRequestType];
}];
[operationManager start];
于 2014-07-11T09:12:24.180 に答える
6

場合によっては、xcode コンパイラで識別子の保持サイクルの問題が発生することがあります。そのため、completedBlock を保持していないことが確実な場合は、次のようなコンパイラ フラグを設定できます。

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"

-(void)someMethod {
}
于 2014-11-26T20:58:53.920 に答える
3

Guillaumeが提供するソリューションを試してみると、デバッグモードではすべて問題ありませんが、リリースモードではクラッシュします。

私のターゲットはiOS4.3であるため、__weakではなく__unsafe_unretainedを使用することに注意してください。

setCompletionBlock:がオブジェクト "request"で呼び出されると、コードがクラッシュします:requestが割り当て解除されました...

したがって、このソリューションはデバッグモードとリリースモードの両方で機能します。

// Avoiding retain cycle :
// - ASIHttpRequest object is a strong property (crashs if local variable)
// - use of an __unsafe_unretained pointer towards self inside block code

self.request = [ASIHttpRequest initWithURL:...
__unsafe_unretained DataModel * dataModel = self;

[self.request setCompletionBlock:^
{
    [dataModel processResponseWithData:dataModel.request.receivedData];        
}];
于 2012-01-16T18:25:29.230 に答える
-6

Apple 開発者 Web サイトのドキュメントをご覧ください: https://developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html#//apple_ref/doc/uid/TP40011029

ページの下部に保持サイクルに関するセクションがあります。

于 2011-08-26T13:23:35.607 に答える