Sì, NSTimer
manterrà un riferimento forte allo target
, che può causare (in particolare nei timer di ripetizione) cicli di riferimento intensi (a.k.a. cicli di conservazione). Nell'esempio, tuttavia, il timer non si ripete e viene ritardato solo 0,5, quindi, nel peggiore dei casi, si avrà un ciclo di riferimento forte che si risolverà automaticamente in 0,5 secondi.
Ma un esempio comune di un ciclo di riferimento forte irrisolto sarebbe avere una UIViewController
con una proprietà NSTimer
che si ripete, ma perché il NSTimer
ha una forte riferimento alla UIViewController
, il controllore finiscono per essere mantenuto.
Quindi, se si mantiene lo NSTimer
come variabile di istanza, quindi, si, è necessario invalidate
per risolvere il ciclo di riferimento forte. Se stai chiamando lo scheduledTimerWithTimeInterval
, ma non lo salverai su una variabile di istanza (come si potrebbe dedurre dal tuo esempio), allora il tuo ciclo di riferimento forte verrà risolto quando lo NSTimer
è completo.
E, a proposito, se hai a che fare con la ripetizione NSTimers
, non cercare di invalidate
loro dealloc
del proprietario del NSTimer
perché il dealloc
, ovviamente, non sarà chiamato fino alla risoluzione del ciclo di riferimento forte. Nel caso di un UIViewController
, ad esempio, è possibile farlo in viewDidDisappear
.
A proposito, il Advanced Memory Management Programming Guide spiega quali sono i forti cicli di riferimento. Chiaramente, questo è in una sezione in cui stanno descrivendo l'uso corretto dei riferimenti deboli, che non è applicabile qui (perché non si ha il controllo sul fatto che NSTimer
utilizza forti riferimenti alla destinazione), ma spiega i concetti di forti cicli di riferimento piacevolmente.
Se non si desidera che il NSTimer
per mantenere un forte riferimento alla self
, in MacOS 10.12 e iOS 10, o più tardi, è possibile utilizzare la resa del blocco e quindi utilizzare il modello weakSelf
:
typeof(self) __weak weakSelf = self;
[NSTimer scheduledTimerWithTimeInterval:0.5 repeats:false block:^(NSTimer * _Nonnull timer) {
[weakSelf showButtons];
}];
A proposito, noto che chiami showButtons
. Se stai cercando di mostrare solo alcuni controlli sulla vostra vista, si potrebbe eliminare l'uso del NSTimer
del tutto e fare qualcosa di simile:
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];
Questo non soffre i problemi di mantenere NSTimer
oggetti, ed esegue sia il ritardo e la visualizzazione aggraziata del pulsante (i) in un'unica istruzione.Se stai eseguendo un'ulteriore elaborazione nel tuo metodo showButtons
, puoi inserirla nel blocco completion
.
Ottima risposta, ma forse non ho chiarito il fatto che in realtà non lo declere nel file .h con il timer NSTimer *, aggiungo quel codice nel file .m, quindi non posso invalidarlo o annullarlo . In questo caso è ancora ok se uso il mio timer, o è meglio usare il codice che mi hai fornito? – Alessandro
@Alessandro In realtà ho presunto che non avessi mantenuto un ivar per il timer. Ma, ovviamente, se vuoi 'invalidare' in' viewWillDisappear', dovrai farlo. (Per inciso, non devi mettere ivar privati nella tua .h; l'estensione della classe privata è migliore.) E un paio di volte hai menzionato sull'impostazione di un 'NSTimer' su' nil'. Si prega di notare che questo non risolve il ciclo di riferimento forte. Il timer deve essere completato (e non ripetuto) o è necessario "invalidare" (utilizzando il nuovo ivar). – Rob