修复警告“在此块中强烈捕获很可能导致启用ARC的代码中的保留周期”
在启用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
相关联。
回复自己:
我对文档的理解是,在block
中使用关键字block
并将variables设置为零后应该没问题,但仍然显示警告。
__block ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:... [request setCompletionBlock:^{ NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil]; request = nil; // .... }];
更新:使用关键字'_ weak'而不是' _block',并使用临时variables:
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
。 相同的行为,但指针保持悬挂,而不是在对象被销毁时自动设置为零。
发生这个问题的原因是你要分配一个块来请求有一个强烈的请求在其中。 该块将自动保留请求,所以原来的请求将不会因循环而释放。 合理?
这很奇怪,因为你用__block标记请求对象,所以它可以引用自己。 你可以通过创build一个弱引用来解决这个问题。
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...]; __weak ASIHTTPRequest *wrequest = request; [request setCompletionBlock:^{ NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil]; // ... }];
这是因为保留了自我。 块将从自己访问,并且自我在块中被引用。 这将创build一个保留周期。
尝试通过创buildself
的弱引用来解决这个问题
__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];
有些时候xcode编译器在保留周期的标识符方面有问题,所以如果你确定你没有保留completionBlock,你可以使用如下的编译器标志:
#pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" #pragma clang diagnostic ignored "-Wgnu" -(void)someMethod { }
当我尝试由Guillaume提供的解决scheme时,在debugging模式下一切正常,但在发布模式下崩溃。
请注意,不要使用__weak,但__unsafe_unretained,因为我的目标是iOS 4.3。
当setCompletionBlock:在对象“请求”上调用时,我的代码崩溃:请求被释放…
所以,这个解决scheme在debugging和发布模式下都可以工作:
// 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]; }];
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:... __block ASIHTTPRequest *blockRequest = request; [request setCompletionBlock:^{ NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:blockRequest.responseData error:nil]; blockRequest = nil; // .... }];
__weak和__block引用有什么区别?
查看Apple开发人员网站上的文档: https : //developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html#//apple_ref/doc/uid/TP40011029
页面底部有一个关于保留周期的部分。