2012-11-23 15 views
9

Kiedy wykonać ten kod:NSTimer zarządzanie pamięcią

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

muszę nil nim lub zwolnić go ot co za zarządzanie pamięcią?

Używam ARC

Odpowiedz

27

Tak, NSTimer będzie utrzymywać silne odniesienie do target, co może powodować (szczególnie w powtarzających się zegarach) silne cykle odniesienia (a.k.a. cykle zatrzymania). W twoim przykładzie zegar nie jest jednak powtarzany, a opóźnienie wynosi tylko 0,5, więc najgorszy scenariusz oznacza, że ​​będziesz mieć silny cykl odniesienia, który automatycznie ustąpi w ciągu 0,5 sekundy.

Ale częstym przykładem nierozwiązanego mocnej cyklu odniesienia byłoby mieć UIViewController z właściwością NSTimer który powtarza się, ale ponieważ NSTimer ma silne odniesienie do UIViewController, kontroler będzie w końcu jest zachowana.

Tak więc, jeśli przechowujesz NSTimer jako zmienną instancji, to tak, powinieneś invalidate, aby rozwiązać silny cykl odniesienia. Jeśli po prostu dzwonisz pod numer scheduledTimerWithTimeInterval, ale nie zapisujesz go do zmiennej instancji (jak można wywnioskować z twojego przykładu), wtedy silny cykl odniesienia zostanie rozwiązany po zakończeniu NSTimer.

I, przy okazji, jeśli masz do czynienia z powtarzającymi się NSTimers, nie próbuj invalidate nich dealloc od właściciela NSTimer ponieważ dealloc oczywiście nie będzie się aż silny cykl odniesienia został rozwiązany. Na przykład w przypadku UIViewController można to zrobić w viewDidDisappear.

Przy okazji, Advanced Memory Management Programming Guide wyjaśnia, czym są silne cykle odniesienia. Najwyraźniej jest to sekcja, w której opisują poprawne użycie słabych odniesień, co nie ma tu zastosowania (ponieważ nie masz kontroli nad tym, że NSTimer używa silnych odniesień do celu), ale wyjaśnia pojęcia z silnym cyklem referencyjnym ładnie.


Jeśli nie chcesz NSTimer utrzymać silne odniesienie do self, w MacOS i iOS 10.12 10 lub później, można użyć odwzorowanie bloku, a następnie użyć weakSelf wzoru:

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

Przy okazji zauważam, że dzwonisz pod numer showButtons. Jeśli starasz się po prostu pokazać niektóre kontrole na widoku, można wyeliminować stosowanie NSTimer całkowicie i zrobić coś takiego:

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]; 

nie cierpią na problemy zachowują NSTimer obiektów i wykonuje zarówno opóźnienie, a także pełne wdzięku przedstawienie przycisku (ów) w jednym komunikacie.Jeśli robisz dodatkowe przetwarzanie w metodzie showButtons, możesz umieścić to w bloku completion.

+0

Świetna odpowiedź, ale być może nie wyjaśniłam, że tak naprawdę nie deklamuję jej w pliku .h z zegarem NSTimer *, po prostu dodajemy ten kod do pliku .m, więc nie mogę go unieważnić ani zlikwidować . Czy w takim przypadku nadal jest dobrze, jeśli korzystam z timera, czy lepiej użyć kodu, który mi podałeś? – Alessandro

+0

@Alessandro Tak naprawdę przypuszczałem, że nie utrzymałeś ivar dla timera. Ale oczywiście, jeśli chcesz "unieważnić" w 'viewWillDisappear', będziesz musiał to zrobić. (Na marginesie, nie musisz umieszczać prywatnych znaków iv w twoim .h; rozszerzenie klasy prywatnej jest lepsze.) I kilka razy wspomniałeś o ustawianiu 'NSTimer' na' zero'. Należy pamiętać, że nie rozwiązuje to silnego cyklu odniesienia. Timer musi albo zakończyć (i nie musi się powtarzać), albo musisz "unieważnić" (używając twojego nowego ivar). – Rob

1

Jeśli zapisujesz je w nieruchomości, to tak, trzeba zrobić, aby ustawić go do zera po opalane selektora.

Można go również bezpiecznie zapisać na wypadek, gdyby twoja klasa została zwolniona z dowolnego powodu, abyś mógł [timer invalidate], jeśli potrzebujesz.

+0

Jeśli się, że właściwość 'weak', nie masz do' zerowe to sam. Uruchamia się automatycznie po wystrzeleniu (zakładając, że nie powtarza się). – Rob

1

Tak, można użyć: myTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(showButtons) userInfo:nil repeats:NO]; a potem w swoim viewDidDisappear [myTimer invalidate]