2017-07-06 1 views
5

Comme nous savons que nous devons utiliser une référence faible à l'intérieur d'un bloc pour briser le cycle de retenir, comme suit:différence entre les références faibles dans un bloc et un NSTimer

__weak id weakSelf = self; 
[self doSomethingWithABlock:^() { 
    [weakSelf doAnotherThing]; 
}] 

Cependant faibles références ne peuvent pas briser le conserver cycle causé par un NSTimer.

__weak id weakSelf = self; 
timer = [NSTimer scheduledTimerWithTimeInterval:30.0f 
             target:weakSelf 
             selector:@selector(tick) 
             userInfo:nil 
             repeats:YES]; // No luck 

Quelle est la différence? Comment la minuterie peut-elle encore retenir la cible?

+0

BTW, nous utilisons généralement 'typeof (self)' plutôt que 'id' pour définir' weakSelf'. – Rob

Répondre

6

Tout le problème avec la technique basée sur le sélecteur NSTimer est qu'il établit une référence forte à l'objet que vous lui passez. Donc, si la variable que vous avez utilisée pour contenir la référence à la cible que vous avez passée à scheduledTimerWithTimeInterval était, elle-même, forte ou faible, est immatérielle. En supposant que la référence target n'était pas nil au moment où le temporisateur planifié basé sur le sélecteur était planifié, NSTimer établira sa propre référence forte. La nature "faible" ou "forte" des références dans le code appelant dicte seulement où ARC placera ses propres appels de gestion de mémoire dans le code de l'appelant, mais le target est juste un simple pointeur, et aucune de ces informations faibles ou fortes n'est transmise à NSTimer. Le sélecteur NSTimer établira sa propre référence forte qui n'est pas résolue jusqu'à ce que le temporisateur soit invalidated. C'est pourquoi, lorsque nous voulons invalider un temporisateur construit via la méthode basée sur le sélecteur, nous devons le viewDidDisappear ou similaire, plutôt que dealloc.

Remarque, scheduledTimerWithTimeInterval a maintenant une variation à base de blocs pour iOS 10 et plus tard, afin que vous puissiez profiter de la configuration de référence faible des blocs si vous n'avez pas en charge les versions antérieures iOS:

typeof(self) __weak weakSelf = self; 
[NSTimer scheduledTimerWithTimeInterval:30 repeats:true block:^(NSTimer * _Nonnull timer) { 
    // use weakSelf here 
}];