修复警告“在此块中强烈捕获[某个对象]可能会导致启用ARC的代码中的保留周期”

时间:2011-08-26 13:10:25

标签: cocoa-touch cocoa asihttprequest automatic-ref-counting retain

在启用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的使用有关。

7 个答案:

答案 0 :(得分:162)

回复自己:

我对文档的理解是说使用关键字block并在块中使用后将变量设置为nil应该没问题,但它仍然会显示警告。

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

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

    }];

更新:让它使用关键字'_ weak'代替' _block',并使用临时变量:

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。

答案 1 :(得分:49)

出现此问题的原因是您正在为请求分配一个块,该请求具有对其中的请求的强引用。该块将自动保留请求,因此原始请求将不会因循环而解除分配。有意义吗?

这很奇怪,因为您使用__block标记请求对象,因此它可以引用自身。你可以通过创建一个弱引用来解决这个问题。

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

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

答案 2 :(得分:12)

由于将自我保留在块中而导致。块将从self访问,self在块中引用。这将创建一个保留周期。

尝试通过创建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];

答案 3 :(得分:6)

有时候xcode编译器在保留周期中存在标识符的问题,所以如果你确定你没有保留completionBlock,你可以放置一个这样的编译器标志:

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

-(void)someMethod {
}

答案 4 :(得分:3)

当我尝试Guillaume提供的解决方案时,在调试模式下一切正常,但在发布模式下崩溃。

请注意,请勿使用__weak但__unsafe_unretained,因为我的目标是iOS 4.3。

在对象“request”上调用setCompletionBlock:时,我的代码崩溃:请求被释放...

因此,此解决方案适用于调试和发布模式:

// 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];        
}];

答案 5 :(得分:2)

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

}];

what the difference between __weak and __block reference?

答案 6 :(得分:-6)