Corrigir aviso “Capturar fortemente neste bloco provavelmente levará a um ciclo de retenção” no código habilitado para ARC

No código habilitado para ARC, como corrigir um aviso sobre um possível ciclo de retenção ao usar uma API baseada em bloco?

O aviso:
Capturing 'request' strongly in this block is likely to lead to a retain cycle

produzido por este trecho de código:

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

O aviso está vinculado ao uso da request object dentro do bloco.

Respondendo a mim mesmo:

Meu entendimento da documentação diz que usar o block palavras-chave e definir a variável como nil após usá-la dentro do bloco deve ser ok, mas ainda mostra o aviso.

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

Atualização: funcionou com a palavra-chave ‘_ weak’ em vez de ‘ _block’ e usando uma variável temporária:

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

Se você também deseja segmentar o iOS 4, use __unsafe_unretained vez de __weak . O mesmo comportamento, mas o ponteiro permanece pendurado em vez de ser automaticamente definido como nulo quando o object é destruído.

O problema ocorre porque você está atribuindo um bloco para solicitar que tenha uma referência forte para solicitar nele. O bloco reterá automaticamente a solicitação, portanto, a solicitação original não será desalocada devido ao ciclo. Faz sentido?

É estranho porque você está marcando o object request com __block para que ele possa se referir a si mesmo. Você pode consertar isso criando uma referência fraca ao lado dela.

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

Isso faz com que se retenha o ego no bloco. O bloco acessará de ego e ego é referido em um bloco. isso criará um ciclo de retenção.

Tente resolver isso criando um refernce fraco de 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]; 

Algumas vezes o compilador xcode tem problemas para identificar os ciclos de retenção, então se você tem certeza de que não está mantendo o completionBlock você pode colocar um sinalizador de compilador como este:

 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-retain-cycles" #pragma clang diagnostic ignored "-Wgnu" -(void)someMethod { } 

Quando eu tento a solução fornecida pelo Guillaume, tudo está bem no modo de debugging, mas falha no modo de lançamento.

Note que não use __weak mas __unsafe_unretained porque meu alvo é o iOS 4.3.

Meu código trava quando setCompletionBlock: é chamado no object “request”: a solicitação foi desalocada …

Portanto, essa solução funciona nos modos Debug e Release:

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

qual a diferença entre a referência __weak e __block?

Dê uma olhada na documentação no site do desenvolvedor da Apple: https://developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html#//apple_ref/doc/uid/TP40011029

Há uma seção sobre reter ciclos na parte inferior da página.

    Intereting Posts