267 votes

Toujours passer une référence faible de soi dans le bloc en ARC ?

Je suis un peu confus au sujet de l'utilisation des blocs en Objective-C. je suis actuellement l'utilisation de l'ARC et j'ai beaucoup de blocs dans mon application, actuellement toujours en se référant à l' self à la place de la faiblesse de son de référence. Cela peut être la cause de ces blocs de soutènement self et de la dealloced ? La question est, dois-je toujours utiliser un weak référence de l' 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);
    }
}

741voto

jemmons Points 5627

Il permet de ne pas se concentrer sur l' strong ou weak de la partie de la discussion. Au contraire l'accent sur le cycle de la partie.

A retenir cycle est une boucle qui se produit lorsque l'Objet A conserve l'Objet B, et l'Objet B conserve Objet A. Dans cette situation, si l'un des objets est sorti:

  • L'objet A ne sera pas libéré parce que l'Objet B contient une référence à elle.
  • Mais l'Objet B ne sera jamais libéré tant qu'Objet Un a une référence à elle.
  • Mais l'Objet A ne sera jamais libérée, parce que l'Objet B contient une référence à elle.
  • à l'infini

Ainsi, ces deux objets seront simplement traîner dans la mémoire pour la durée du programme, même si elles devraient, si tout fonctionne correctement, être libéré.

Donc, ce que nous préoccupe est de retenir les cycles, et il n'y a rien sur les blocs de dans et d'eux-mêmes qui créent ces cycles. Ce n'est pas un problème, par exemple:

[myArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
   [self doSomethingWithObject:obj];
}];

Le bloc conserve self, mais self ne conserve pas les bloquer. Si l'un ou l'autre est sorti, pas de cycle est créé et tout est désalloué comme il se doit.

Lorsque vous avez un problème est quelque chose comme:

//In the interface:
@property (strong) void(^myBlock)(id obj, NSUInteger idx, BOOL *stop);

//In the implementation:
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [self doSomethingWithObj:obj];     
}];

Maintenant, votre objet (self) a explicitement strong de référence pour le bloc. Et le bloc a un implicite référence forte à l' self. C'est un cycle, et maintenant pas d'objet sera libéré correctement.

Parce que, dans ce genre de situation, self , par définition, a déjà strong de référence pour le bloc, il est généralement plus simple à résoudre en faisant explicitement référence faible pour self pour le bloc à utiliser:

__weak MyObject *weakSelf = self;
[self setMyBlock:^(id obj, NSUInteger idx, BOOL *stop) {
  [weakSelf doSomethingWithObj:obj];     
}];

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 devrait être utilisé pour briser ce qui serait autrement un cycle de conserver entre soi et le bloc. Si vous étiez à adopter ce modèle partout, on pourrait courir le risque de passage d'un bloc à quelque chose qui ont été exécutés après l' self a été libéré.

//SUSPICIOUS EXAMPLE:
__weak MyObject *weakSelf = self;
[[SomeOtherObject alloc] initWithCompletion:^{
  //By the time this gets called, "weakSelf" might be nil because it's not retained!
  [weakSelf doSomething];
}];

26voto

Leo Natan Points 25262

Vous n’avez pas à toujours utiliser une référence faible. Si votre bloc est pas conservé, mais exécutée et ensuite rejeté, vous pouvez capturer soi fortement, puisqu’elle ne crée pas un cycle de conserver. Dans certains cas, vous voulez même le bloc de tenir soi jusqu'à la fin du bloc, donc il ne pas libérer prématurément. Si, toutefois, vous capturez le bloc fortement, et à l’intérieur de capture auto, il va créer un cycle de conserver.

19voto

Rob Points 70987

De Léo souligne le, le code que vous avez ajouté à votre question n'est pas de suggérer une forte cycle de référence (un.k.un., conserver cycle). Une opération liée problème qui pouvait provoquer une forte cycle de référence serait le cas si l'opération n'est pas libérée. Alors que votre extrait de code suggère que vous n'avez pas défini votre opération d'être concurrentes, mais si vous avez, il ne serait pas échapper si vous n'avez jamais posté isFinished, ou si vous avez eu des dépendances circulaires, ou quelque chose comme ça. Et si l'opération n'est pas libérée, la vue contrôleur ne serait pas publié. Je suggère l'ajout d'un point d'arrêt ou d' NSLog dans la dealloc méthode et de confirmer que l'appelé.

Vous avez dit:

Je comprends la notion de conserver les cycles, mais je ne suis pas tout à fait sûr de ce qui se passe dans les blocs, de sorte que me confond un peu

Le conserver cycle (fort de cycle de référence) les problèmes qui se produisent avec les blocs sont tout comme les conserver cycle questions que vous êtes familier avec. Un bloc de maintenir de solides références à des objets qui apparaissent dans le bloc, et elle ne dégage pas de ces solides références jusqu'à ce que le bloc lui-même est libéré. Ainsi, si les références de bloc self, ou même simplement fait référence à une variable d'instance d' self, qui permettra de maintenir une forte référence à soi-même, qui n'est pas résolu jusqu'à ce que le bloc est libérée (ou dans ce cas, jusqu'à l' NSOperation sous-classe est libéré.

Pour plus d'informations, voir l' Éviter les Forte des Cycles de Référence lors de la Capture de l'auto section de la Programmation Objective-C: Travailler avec des Blocs de document.

Si votre vue-contrôleur est pas encore libérée, il suffit d'identifier où le suspens, une forte référence de résidence (en supposant que vous avez confirmé l' NSOperation est d'obtenir libéré). Un exemple courant est l'utilisation d'une répétition NSTimer. Ou de la coutume, delegate ou d'un autre objet qui est, à tort, le maintien d'un strong de référence. Vous pouvez souvent utiliser des Instruments de la piste vers le bas, où les objets sont l'obtention de leur forte références, par exemple:

record reference counts

0voto

Danyun Points 925

Quelques explications ignorer une condition sur le cycle de conserver [si un groupe d’objets est connecté par un cercle de relations solides, ils gardent l’autre vivant même s’il n’y a pas de références fortes d’en dehors du groupe.] Pour plus d’informations, consultez le document

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