cocoa touch - Corrigir aviso “Capturar[um objeto] com força nesse bloco provavelmente levará a um ciclo de retenção” no código habilitado para ARC




cocoa-touch asihttprequest (5)

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á retendo 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 {
}

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 objeto dentro do bloco.



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

Quando eu tento a solução fornecida pelo Guillaume, tudo está bem no modo de depuração, 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 objeto "request": a solicitação foi desalocada ...

Portanto, essa solução funciona nos modos de depuração e liberação:

// 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 referência __weak e __block?





retain