Corrige la advertencia "Capturar [un objeto] fuertemente en este bloque es probable que conduzca a un ciclo de retención" en el código habilitado para arco


En el código habilitado para ARC, ¿cómo corregir una advertencia sobre un ciclo de retención potencial cuando se usa una API basada en bloques?

La advertencia:
Capturing 'request' strongly in this block is likely to lead to a retain cycle

Producido por este fragmento de código:

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

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

La advertencia está vinculada al uso del objeto request dentro del bloque.

Author: barfoon, 2011-08-26

7 answers

Respondiéndome a mí mismo:

Mi comprensión de la documentación dice que usar la palabra clave block y establecer la variable en nil después de usarla dentro del bloque debería estar bien, pero todavía muestra la advertencia.

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

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

    }];

Actualización: consiguió que funcionara con la palabra clave '_weak 'en lugar de' _block', y usando una variable temporal:

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

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

Si también desea apuntar a iOS 4, use __unsafe_unretained en lugar de __weak. El mismo comportamiento, pero el puntero permanece colgando en lugar de se establece automáticamente en nil cuando se destruye el objeto.

 161
Author: Guillaume,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-07 15:30:13

El problema ocurre porque está asignando un bloque a request que tiene una fuerte referencia a request en él. El bloque retendrá automáticamente la solicitud, por lo que la solicitud original no se desasignará debido al ciclo. Sentido?

Es raro porque estás etiquetando el objeto request con __block para que pueda referirse a sí mismo. Puede arreglar esto creando una referencia débil junto con.

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

[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil];
    // ...
    }];
 48
Author: ZaBlanc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-07 15:00:48

Causa debido a la retención del yo en el bloque. Block se accederá desde self, y self se refiere en block. esto creará un ciclo de retención.

Intenta resolver esto creando una referencia débil 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];
 11
Author: HDdeveloper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-11 09:12:24

Algunas veces el compilador xcode tiene problemas para identificar los ciclos de retención, por lo que si está seguro de que no está reteniendo el bloque de terminación, puede poner una bandera de compilador como esta:

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

-(void)someMethod {
}
 6
Author: GOrozco58,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-26 20:58:53

Cuando pruebo la solución proporcionada por Guillaume, todo está bien en el modo de depuración, pero se rompe en el modo de liberación.

Tenga en cuenta que no use __weak pero __unsafe_unretained porque mi objetivo es iOS 4.3.

Mi código se bloquea cuando se llama a setCompletionBlock: en el objeto "request" : request fue desasignado ...

Por lo tanto, esta solución funciona tanto en los modos de depuración como de liberación:

// 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];        
}];
 3
Author: squall2022,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-16 18:25:29
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...
__block ASIHTTPRequest *blockRequest = request;
[request setCompletionBlock:^{
    NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:blockRequest.responseData error:nil];
    blockRequest = nil;
// ....

}];

¿Cuál es la diferencia entre __débil y _ _ referencia de bloque?

 2
Author: Emil Marashliev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:18:10

Echa un vistazo a la documentación en el sitio web del desarrollador de Apple: https://developer.apple.com/library/prerelease/ios/#documentation/General/Conceptual/ARCProgrammingGuide/Introduction.html#//apple_ref/doc/uid/TP40011029

Hay una sección sobre los ciclos de retención en la parte inferior de la página.

 -6
Author: Nyx0uf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-08-26 13:23:35