cocoa touch - Advertencia de reparación "Capturar[un objeto] con fuerza en este bloque es probable que conduzca a un ciclo de retención" en el código habilitado para ARC
cocoa-touch asihttprequest (7)
En el código habilitado para ARC, ¿cómo arreglar una advertencia sobre un posible ciclo de retención, 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 de la request
del objeto dentro del bloque.
Algunas veces el compilador de xcode tiene problemas para el identificador de los ciclos de retención, por lo que si está seguro de que no retiene el bloque de ejecución puede poner un indicador de compilación así:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
-(void)someMethod {
}
Causa debido a la retención del yo en el bloque. Se accederá al bloque desde uno mismo, y el self se refiere al bloque. 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];
Cuando intento la solución proporcionada por Guillaume, todo está bien en el modo de depuración, pero se bloquea en el modo de lanzamiento.
Tenga en cuenta que no use __weak pero __unsafe_unretained porque mi objetivo es iOS 4.3.
Mi código se bloquea cuando setCompletionBlock: se invoca al objeto "solicitud": la solicitud se desasignó ...
Entonces, 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];
}];
Eche un vistazo a la documentación en el sitio web para desarrolladores 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 retener ciclos en la parte inferior de la página.
El problema ocurre porque está asignando un bloque para solicitar que tenga una referencia fuerte para solicitarlo. El bloque retendrá automáticamente la solicitud, por lo que la solicitud original no se desasignará debido al ciclo. ¿Tener sentido?
Es extraño porque está etiquetando el objeto de solicitud con __block para que pueda referirse a sí mismo. Puede solucionar esto creando una referencia débil junto a él.
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...];
__weak ASIHTTPRequest *wrequest = request;
[request setCompletionBlock:^{
NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:wrequest.rawResponseData error:nil];
// ...
}];
Respondiendo a mí mismo:
Mi comprensión de la documentación dice que usar block
palabras clave y establecer la variable como nula después de usarlo dentro del bloque debería estar bien, pero aún muestra la advertencia.
__block ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...
[request setCompletionBlock:^{
NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:request.responseData error:nil];
request = nil;
// ....
}];
Actualización: lo tengo que trabajar 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
lugar de __weak
. Mismo comportamiento, pero el puntero permanece colgando en lugar de establecerse automáticamente en cero cuando se destruye el objeto.
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:...
__block ASIHTTPRequest *blockRequest = request;
[request setCompletionBlock:^{
NSDictionary *jsonDictionary = [[CJSONDeserializer deserializer] deserialize:blockRequest.responseData error:nil];
blockRequest = nil;
// ....
}];