web-dev-qa-db-fra.com

Est-il nécessaire d'utiliser des références faibles à soi toujours à l'intérieur des blocs ..?

Je suis confondu avec l'utilisation de blocs internes, je passe en revue certains documents d'Apple mais je ne trouve toujours pas la bonne réponse.

Certaines personnes disent toujours utiliser le soi faible à l'intérieur des blocs, mais certains disent utiliser le soi faible dans les blocs copiés, pas nécessaire de toujours utiliser.

Échantillon 1:

self.handler = ^(id response, NSError *error)
{
    self.newresponse = response; //use weak self here
};  

Échantillon 2:

Utiliser un soi faible;

__weak myViewController *weakSelf = self;

[UIView animateWithDuration:interval delay:0.0 options:curve animations:^
{
    [weakSelf.view.superview setTransform:CGAffineTransformMakeTranslation(0, -106)];
    //in above is it use of weak is neassary 
}
completion:^(BOOL finished)
{

}];

Sans moi faible;

__weak myViewController *weakSelf = self;

[UIView animateWithDuration:interval delay:0.0 options:curve animations:^
{
    [myViewController.view.superview setTransform:CGAffineTransformMakeTranslation(0, -106)];

}
completion:^(BOOL finished)
{

}];

Dans les exemples ci-dessus, lesquels sont corrects…? ** J'utilise ARC

43
ShivaPrasad

Vous devez uniquement utiliser une référence faible à self, si self conserve une référence du bloc.

Dans votre exemple, vous ne conservez pas de référence à votre bloc dans self, vous utilisez uniquement des blocs en ligne avec le UIView animateWithDuration:, et en tant que tel, il n'est pas nécessaire d'utiliser __weak myViewController *weakSelf = self;

Pourquoi est-ce le cas? Parce qu'un bloc conservera des références fortes à toutes les variables qu'il utilise de la classe utilisant le bloc. Cela inclut self. Maintenant, si l'instance de classe elle-même conserve une référence forte au bloc et que le bloc conserve une référence forte à l'instance de classe, vous avez un cycle de conservation, ce qui entraînera des fuites de mémoire.

76
WDUK

Voici un code qui illustre la réponse de @ WDUK:

typedef void (^SimpleBlock)();

@interface ObjectThatRetainsBlock : NSObject
@property(nonatomic, strong) SimpleBlock block;
@end

@implementation ObjectThatRetainsBlock

- (instancetype)init {
  self = [super init];
  if (self) {
    self.block = ^{ NSLog(@"Running block in %@", self); };
    self.block();
  }
  return self;
}

- (void)dealloc {
  NSLog(@"ObjectThatRetainsBlock is deallocated.");
}

@end

@interface ObjectThatDoesNotRetainBlock : NSObject
@end

@implementation ObjectThatDoesNotRetainBlock

- (instancetype)init {
  self = [super init];
  if (self) {
    SimpleBlock block = ^{ NSLog(@"Running block in %@", self); };
    block();
  }
  return self;
}

- (void)dealloc {
  NSLog(@"ObjectThatDoesNotRetainBlock is deallocated.");
}

@end

- (void)test {
  ObjectThatRetainsBlock *objectThatRetainsBlock =
      [[ObjectThatRetainsBlock alloc] init];
  ObjectThatDoesNotRetainBlock *objectThatDoesNotRetainBlock = 
      [[ObjectThatDoesNotRetainBlock alloc] init];
}

La méthode test affiche:

Running block in <ObjectThatRetainsBlock: 0x7f95f3335e50>
Running block in <ObjectThatDoesNotRetainBlock: 0x7f95f3335c50>
ObjectThatDoesNotRetainBlock is deallocated.

Remarquez que dans la méthode init de ObjectThatDoesNotRetainBlock, nous créons block comme un ivar, mais lorsque le block sort du domaine d'application, nous ne gardons pas une référence à elle.

Dans la méthode test, lorsque les deux objets sortent de la portée, observez que objectThatDoesNotRetainBlock est désalloué car il ne fait pas partie d'un cycle de conservation.

En revanche, objectThatRetainsBlock n'est pas désalloué, car il fait partie d'un cycle de rétention. Il conserve le bloc au-delà de la portée de l'appel de méthode.

Si vous voulez une autre explication, voir cette réponse .

10
Rose Perrone