140 votes

Difficulté de mise en garde « Capturing [un objet] fortement en ce bloc est susceptible d’entraîner un cycle de conserver » dans le code compatible ARC

Dans le code de l’ARC a permis, comment réparer un avertissement concernant un potentiel retain cycle, lorsque vous utilisez une API basée sur le bloc ?

La mise en garde :
``

produit par cet extrait de code :

Mise en garde est liée à l’utilisation de l’objet `` à l’intérieur du bloc.

164voto

Guillaume Points 11397

Réponse à moi-même:

Ma compréhension de la documentation dit que utilisant le mot - block et réglage de la variable à zéro après l'avoir utilisé à l'intérieur du bloc devrait être ok, mais il affiche toujours le message d'avertissement.

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

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

    }];

Mise à jour: l'ai eu à travailler avec le mot-clé '_faiblesse "au lieu de"_block", et à l'aide d'une variable temporaire:

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

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

Si vous souhaitez également cible iOS 4, utilisez __unsafe_unretained au lieu de __weak. Même comportement, mais le pointeur reste bancale au lieu d'être automatiquement mis à zéro lorsque l'objet est détruit.

49voto

ZaBlanc Points 2396

Le problème se produit car vous affectez un bloc à la requête qui a une référence forte à demander. Le bloc conservera automatiquement la demande, de sorte que la demande d'origine ne sera pas désallouée à cause du cycle. Avoir du sens?

C'est juste bizarre parce que vous étiquetez l'objet de requête avec __block pour qu'il puisse se référer à lui-même. Vous pouvez résoudre ce problème en créant une référence faible à côté .

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

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

12voto

HDdeveloper Points 1439

Cela provoque la rétention de soi dans le bloc. La volonté de bloc accessible depuis soi-même et soi-même est référencé en bloc. Cela créera un cycle de conservation.

Essayez de résoudre ceci en créant une faible référence 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];
 

3voto

squall2022 Points 64

Lorsque j'essaie la solution fournie par Guillaume, tout se passe bien en mode Debug, mais il se bloque en mode Release.

Notez que n'utilisez pas __weak mais __unsafe_unretained car ma cible est iOS 4.3.

Mon code se bloque lorsque setCompletionBlock: est appelé sur l'objet "request": la requête a été libérée ...

Donc, cette solution fonctionne à la fois dans les modes Debug et 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];        
}];
 

2voto

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

}];
 

Quelle est la différence entre __weak et la référence __block?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X