2012-11-23 16 views
9

Quando eseguo questo codice:NSTimer gestione della memoria

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

Ho bisogno di nullo o rilasciarlo, ot tutto ciò per la gestione della memoria?

Sto usando ARC

risposta

27

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.

+0

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

+0

@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

1

Se si salva in una proprietà, allora sì, si ha bisogno di impostarla a zero dopo aver sparato il selettore.

È anche sicuro salvarlo nel caso in cui la classe venga deallocata per qualsiasi motivo, in modo da poterlo fare [timer invalidate] se necessario.

+0

Se fare che la proprietà 'weak', non c'è bisogno di' quelle negative da soli. Si rilascerà automaticamente dopo che si è attivato (supponendo che non sia ripetuto). – Rob

1

Sì, è possibile utilizzare: myTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO]; E poi nel vostro viewDidDisappear [myTimer invalidate]