Vraag NSTimer geheugenbeheer


Wanneer ik deze code uitvoer:

[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO];

moet ik het losmaken of loslaten, ongeacht wat voor geheugenbeheer?

Ik gebruik ARC


10
2017-11-23 19:10


oorsprong


antwoorden:


Ja, NSTimer zal een sterke verwijzing naar de target, wat kan veroorzaken (vooral in herhalende timers) sterke referentiecycli (a.k.a.cycli behouden). In uw voorbeeld herhaalt de timer zich echter niet en heeft hij slechts 0,5 vertraging, dus in het slechtste geval heeft u een sterke referentiecyclus die zichzelf automatisch in 0,5 seconde zal oplossen.

Maar een algemeen voorbeeld van een onopgeloste sterke referentiecyclus zou zijn om een UIViewController met een NSTimer eigenschap die zich herhaalt, maar omdat de NSTimer heeft een sterke verwijzing naar de UIViewController, de controller zal uiteindelijk worden vastgehouden.

Dus, als je de NSTimer als een instantievariabele, dan, ja, zou je dat moeten doen invalidate om de sterke referentiecyclus op te lossen. Als je gewoon de scheduledTimerWithTimeInterval, maar niet opslaan in een instantievariabele (zoals uit uw voorbeeld kan worden afgeleid), dan zal uw sterke referentiecyclus worden opgelost wanneer de NSTimer is compleet.

En trouwens, als je te maken hebt met herhalen NSTimers, probeer het niet invalidate ze in dealloc van de eigenaar van de NSTimer omdat het dealloc uiteraard zal niet worden aangeroepen totdat de sterke referentiecyclus is opgelost. In het geval van een UIViewControllerje zou het bijvoorbeeld kunnen doen viewDidDisappear.

Trouwens, de Geavanceerde programmeerhandleiding voor geheugenbeheer legt uit wat sterke referentiecycli zijn. Dit is duidelijk in een gedeelte waarin ze het juiste gebruik van zwakke referenties beschrijven, wat hier niet van toepassing is (omdat je geen controle hebt over het feit dat NSTimer gebruikt sterke verwijzingen naar het doel), maar het verklaart de concepten van sterke referentiecycli mooi.


Als je je niet wilt NSTimer om een ​​sterke verwijzing naar te houden self, in macOS 10.12 en iOS 10 of hoger kunt u de blokweergave gebruiken en vervolgens de weakSelf patroon:

typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:0.5 repeats:false block:^(NSTimer * _Nonnull timer) {
    [weakSelf showButtons];
}];

Trouwens, ik merk dat je belt showButtons. Als u alleen bepaalde bedieningselementen in uw weergave wilt weergeven, kunt u het gebruik van de NSTimer helemaal en doe zoiets als:

self.button1.alpha = 0.0;
self.button2.alpha = 0.0;

[UIView animateWithDuration:0.25
                      delay:0.5
                    options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionAllowUserInteraction
                 animations:^{
                     self.button1.alpha = 1.0;
                     self.button2.alpha = 1.0;
                 }
                 completion:nil];

Dit lijdt niet onder de behoudsproblemen van NSTimer objecten, en voert zowel de vertraging als de sierlijke weergave van de knop (pen) uit, allemaal in één instructie. Als u aanvullende verwerking in uw doet showButtons methode, kun je dat in de completion blok.


28
2017-11-23 19:25



Als u het in een eigenschap opslaat, ja, moet u dit op nul zetten nadat het de selector heeft geactiveerd.

Het is ook veilig om het op te slaan voor het geval je klas om welke reden dan ook wordt verwijderd, zodat je het kunt doen [timer invalidate] als je moet.


1
2017-11-23 19:16



Ja, je kunt gebruiken: myTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO]; En dan is het volgens jou mogelijk [myTimer invalidate]


1
2017-11-23 19:36