Je suis un peu confus quant à l'utilisation des blocs dans Objective-C. J'utilise actuellement ARC et j'ai beaucoup de blocs dans mon application, faisant toujours référence à la self
place de sa référence faible. Cela peut-il être la raison pour laquelle ces blocs le retiennent self
et l'empêchent d'être désalloué? La question est, dois-je toujours utiliser une weak
référence de self
dans un bloc?
-(void)handleNewerData:(NSArray *)arr
{
ProcessOperation *operation =
[[ProcessOperation alloc] initWithDataToProcess:arr
completion:^(NSMutableArray *rows) {
dispatch_async(dispatch_get_main_queue(), ^{
[self updateFeed:arr rows:rows];
});
}];
[dataProcessQueue addOperation:operation];
}
ProcessOperation.h
@interface ProcessOperation : NSOperation
{
NSMutableArray *dataArr;
NSMutableArray *rowHeightsArr;
void (^callback)(NSMutableArray *rows);
}
ProcessOperation.m
-(id)initWithDataToProcess:(NSArray *)data completion:(void (^)(NSMutableArray *rows))cb{
if(self =[super init]){
dataArr = [NSMutableArray arrayWithArray:data];
rowHeightsArr = [NSMutableArray new];
callback = cb;
}
return self;
}
- (void)main {
@autoreleasepool {
...
callback(rowHeightsArr);
}
}
Réponses:
Cela aide à ne pas se concentrer sur la partie
strong
ou laweak
partie de la discussion. Concentrez-vous plutôt sur la partie cycle .Un cycle de rétention est une boucle qui se produit lorsque l’objet A conserve l’objet B et que l’ objet B conserve l’objet A. Dans ce cas, si l’un ou l’autre des objets est libéré:
Ainsi, ces deux objets resteront simplement en mémoire pendant toute la durée de vie du programme, même s'ils doivent, si tout fonctionnait correctement, être désalloués.
Donc, ce qui nous inquiète, c'est de conserver les cycles , et il n'y a rien sur les blocs en soi qui créent ces cycles. Ce n'est pas un problème, par exemple:
Le bloc conserve
self
, maisself
ne conserve pas le bloc. Si l'un ou l'autre est libéré, aucun cycle n'est créé et tout est désalloué comme il se doit.Là où vous avez des ennuis, c'est quelque chose comme:
Maintenant, votre objet (
self
) a unestrong
référence explicite au bloc. Et le bloc a une référence forte implicite àself
. C'est un cycle, et maintenant aucun objet ne sera désalloué correctement.Parce que, dans une situation comme celle-ci,
self
par définition a déjà unestrong
référence au bloc, il est généralement plus facile à résoudre en faisant une référence explicitement faible auself
bloc à utiliser:Mais cela ne devrait pas être le modèle par défaut que vous suivez lorsque vous traitez avec des blocs qui appellent
self
! Cela ne doit être utilisé que pour rompre ce qui serait autrement un cycle de rétention entre soi et le bloc. Si vous deviez adopter ce modèle partout, vous courriez le risque de passer un bloc à quelque chose qui a été exécuté après avoirself
été désalloué.la source
-setCompleteionBlockWithSuccess:failure:
méthode. Mais sipaginator
est détenu parViewController
, et que ces blocs ne sont pas appelés aprèsViewController
être libérés, l'utilisation d'une__weak
référence serait le mouvement sûr (car ilself
possède la chose qui possède les blocs, et il est donc probable qu'il soit toujours là lorsque les blocs l'appellent même s'ils ne le conservent pas). Mais cela fait beaucoup de «si». Cela dépend vraiment de ce que cela est censé faire.MyObject
et lesSomeOtherObject
deux possèdent le bloc. Mais parce que la référence du blocMyObject
estweak
, le bloc n'est pas propriétaireMyObject
. Ainsi, alors que le bloc est garanti d'exister aussi longtemps que l' unMyObject
ou l' autreSomeOtherObject
existe, il n'y a aucune garantie quiMyObject
existera aussi longtemps que le bloc existera.MyObject
peut être complètement désalloué et, tantSomeOtherObject
qu'il existe, le bloc sera toujours là.Vous n'êtes pas obligé de toujours utiliser une référence faible. Si votre bloc n'est pas conservé, mais exécuté puis rejeté, vous pouvez vous capturer fortement, car cela ne créera pas de cycle de conservation. Dans certains cas, vous souhaitez même que le bloc se maintienne jusqu'à la fin du bloc afin qu'il ne se désalloue pas prématurément. Cependant, si vous capturez fortement le bloc et que vous vous capturez à l'intérieur, cela créera un cycle de rétention.
la source
Je suis totalement d'accord avec @jemmons:
Pour surmonter ce problème, on peut définir une référence forte sur l'
weakSelf
intérieur du bloc:la source
->
), où vous voulez garantir que vous avez réellement obtenu une référence valide et la conserver en continu sur l'ensemble des opérations, par exempleif ( strongSelf ) { /* several operations */ }
Comme Leo le fait remarquer, le code que vous avez ajouté à votre question ne suggère pas un cycle de référence solide (aka, cycle de conservation). Un problème lié à l'opération qui pourrait provoquer un cycle de référence fort serait si l'opération n'est pas libérée. Bien que votre extrait de code suggère que vous n'avez pas défini votre opération comme étant simultanée, mais si vous l'avez, elle ne sera pas publiée si vous n'avez jamais publié
isFinished
, ou si vous aviez des dépendances circulaires, ou quelque chose comme ça. Et si l'opération n'est pas validée, le contrôleur de vue ne le sera pas non plus. Je suggère d'ajouter un point d'arrêt ouNSLog
dans ladealloc
méthode de votre opération et de confirmer que cela est appelé.Tu as dit:
Les problèmes de cycle de rétention (cycle de référence fort) qui se produisent avec les blocs sont similaires aux problèmes de cycle de rétention que vous connaissez. Un bloc conservera des références fortes à tous les objets qui apparaissent dans le bloc, et il ne libérera pas ces références fortes jusqu'à ce que le bloc lui-même soit libéré. Ainsi, si le bloc fait référence
self
, ou même fait simplement référence à une variable d'instance deself
, qui maintiendra une référence forte à soi, cela n'est pas résolu jusqu'à ce que le bloc soit libéré (ou dans ce cas, jusqu'à ce que laNSOperation
sous-classe soit libérée.Pour plus d'informations, consultez la section Évitez les cycles de référence forts lors de la capture de l'auto- section du document Programmation avec Objective-C: Travailler avec des blocs .
Si votre contrôleur de vue n'est toujours pas libéré, il vous suffit d'identifier où réside la référence forte non résolue (en supposant que vous avez confirmé que la
NSOperation
désallocation est en cours). Un exemple courant est l'utilisation d'une répétitionNSTimer
. Ou undelegate
objet personnalisé ou autre qui maintient par erreur unestrong
référence. Vous pouvez souvent utiliser des instruments pour localiser où les objets obtiennent leurs références fortes, par exemple:Ou dans Xcode 5:
la source
Quelques explications ignorer une condition sur le cycle de conserver [Si un groupe d'objets est relié par un cercle de relations solides, ils se tiennent mutuellement en vie , même s'il n'y a pas de solides références à l' extérieur du groupe.] Pour plus d' informations, lire le document de
la source
Voici comment vous pouvez utiliser le self à l'intérieur du bloc:
// appel du bloc
la source