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
하고 변수를 블록 내에서 사용한 후 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로 설정되는 대신 매달려 있습니다.
답변
이 요청은 요청에 대한 강력한 참조가있는 요청에 블록을 할당하기 때문에 발생합니다. 블록은 자동으로 요청을 유지하므로 주기로 인해 원래 요청이 할당 해제되지 않습니다. 말이 되나요?
__block으로 요청 객체에 태그를 지정하여 자체를 참조 할 수 있기 때문에 이상합니다. 약한 참조를 옆에 만들어서이 문제를 해결할 수 있습니다 .
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...];
__weak ASIHTTPRequest *wrequest = request;
[request setCompletionBlock:^{
NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil];
// ...
}];
답변
블록에 자기를 유지하기 때문에 발생합니다. 블록은 자체에서 액세스되며 자체는 블록에서 참조됩니다. 유지주기가 생성됩니다.
약한 참조를 생성하여이 문제를 해결하십시오. 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 컴파일러는 유지주기를 식별하는 데 문제가 있기 때문에 completionBlock을 유지하지 않는 경우 다음과 같이 컴파일러 플래그를 넣을 수 있습니다.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
-(void)someMethod {
}
답변
Guillaume에서 제공하는 솔루션을 시도하면 디버그 모드에서는 모든 것이 정상이지만 릴리스 모드에서는 충돌합니다.
내 목표는 iOS 4.3이므로 __weak을 사용하지 않고 __unsafe_unretained를 사용하십시오.
객체 “요청”에서 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];
}];
답변
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...
__block ASIHTTPRequest *blockRequest = request;
[request setCompletionBlock:^{
NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:blockRequest.responseData error:nil];
blockRequest = nil;
// ....
}];
답변
Apple 개발자 웹 사이트 ( https://developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html#//apple_ref/doc/uid/TP40011029) 에서 설명서를 살펴보십시오.
페이지 하단에 유지주기에 대한 섹션이 있습니다.
