修正了启用 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的使用。

48213 次浏览

我自言自语道:

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

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


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


}];

更新: 让它使用关键字“ _ “弱”而不是“弱” _ block”,并使用一个临时变量:

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


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

如果您还希望将 iOS4作为目标,请使用 __unsafe_unretained而不是 __weak。同样的行为,但是指针保持悬空状态,而不是在对象被销毁时自动设置为 nil。

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

请注意,不要使用 _ _ 孱弱但 _ _ 不安全 _ 不保留,因为我的目标是 iOS 4.3。

当对象“ request”调用 setCompletionBlock: 时,我的代码崩溃: 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];
}];

之所以会出现这个问题,是因为您要为请求分配一个块,该块中包含对请求的强引用。该块将自动保留请求,因此原始请求不会因为循环而释放。有道理吗?

这很奇怪,因为您正在用 _ _ block 标记请求对象,以便它可以引用自己。您可以通过创建一个弱引用 并肩作战来修复它。

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


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


}];

弱引用和块引用的区别是什么?

它的原因是由于保留在块自我。块将从 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];

有时候 xcode 编译器在标识保留循环方面有问题,所以如果你确定你没有保留补全块,你可以放一个编译器标志如下:

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


-(void)someMethod {
}