2009-06-23 27 views
22

Mam czasomierz, który uruchamia się po wywołaniu metody viewWillAppear i unieważnia po wywołaniu metody viewDidDisappear. Ale po pewnej ilości przełączania między widokami timer kontynuuje strzelanie nawet po jego unieważnieniu. Jaki jest problem?NSTimer nie zatrzymuje się

Oto mój kod:

NSTimer *timer; 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f 
        target: self 
        selector:@selector(timerAction) 
        userInfo:nil 
        repeats:YES]; 
} 

-(void)viewDidDisappear:(BOOL)animated { 
    [super viewDidDisappear:animated]; 
    [timer invalidate]; 
    timer = nil; 
} 

-(void) timerAction 
{ 
    NSLog(@"timerAction"); 
} 

Odpowiedz

37

Powinienem był zachować link do zegara, zachowując go. :) Zadałem to pytanie 5 miesięcy temu, a to niesamowite, o ile więcej nabrałem doświadczenia. :)

timer = [ [NSTimer scheduledTimerWithTimeInterval: ...] retain]; 
... 
... 
[timer invalidate]; 
[timer release]; 
+0

Jak to zrobić w ARC, gdy 'keep 'i' release' są niedozwolone? –

+1

Dla iOS 7/8, patrz odpowiedź poniżej na temat korzystania z pary zegarów 'repeats: NO'. –

0

Zapomniałeś aby zwolnić licznik w viewWillDisappear:

- (void)viewDidDisappear:(BOOL)animated 
{ 
    [super viewDidDisappear:animated]; 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
} 

To nie powinno powodować stoper zachować wypalania chociaż ...

+1

w tym przypadku aplikacji miażdży bo zegar jest już zwolniony. –

+0

Ben Gotow ma właściwą odpowiedź tutaj. Musisz zachować timer po jego utworzeniu, a następnie unieważnić i zwolnić, gdy chcesz, aby przestał do Ciebie oddzwaniać – rpetrich

+0

Nie masz/nie chcesz go zachować, ponieważ pętla uruchamiania to zrobi, ale jest to dobry pomysł, jeśli chcesz być bezpieczny. – Wevah

0

Z invalidate z doco mówi

"Pętla uruchamiania usuwa i zwalnia timer, tuż przed powrotem metody unieważniającej lub w jakimś późniejszym punkcie."

Przypuszczam, że Twój jest usuwany w pewnym późniejszym momencie.

6

metody nazywanej przez czasomierz powinien mieć definicji

- (void)methodName:(NSTimer *)aTimer; 

ten sposób metoda ma tę instancję zegar, który został zwolniony. W jaki sposób to robisz, metoda nie będzie wiedzieć, czy licznik czasu został unieważniony, czy nie.

Spróbuj zmienić inicjalizacji timera do

timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f target: self selector:@selector(timerAction:) userInfo:nil repeats:YES] 

i metoda

-(void) timerAction:(NSTimer *)aTimer{...} 

nadzieję, że pomoże

+0

Nie będzie to miało żadnego efektu. – rpetrich

+0

@rpetrich Jeśli możesz podać jeszcze mniej informacji w swojej odpowiedzi, to byłby świetny gość! –

+1

Unieważnij obiekt timera w metodzie i ustaw go jako zero. Upewnij się także, że NSTimer jest zadeklarowany jako właściwość retain. To działa dla mnie. –

2

To może nie być problemem, ale trzeba zachować odniesienie do timer zwrócony z pliku scheduleTimerWithInterval :. Bez tego wskaźnik na zegar może być nieważny do czasu, gdy go przerwiesz.

- (void)viewWillAppear:(BOOL)animated 
{ 
    [super viewWillAppear:animated]; 
    timer = [[NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:@selector(timerAction) userInfo:nil repeats:YES] retain]; 
} 

- (void)viewDidDisappear:(BOOL)animated 
{ 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
    [super viewDidDisappear:animated]; 
} 

- (void)dealloc 
{ 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
    [super dealloc]; 
} 

Spróbuj także ustawić punkt przerwania w viewDidDisappear i upewnij się, że jest wywoływany!

0

Miałem ten sam problem.

nie mogę dealloc moje wystąpienie jeśli zegar nadal działa, więc muszę go zatrzymać przed wywołaniem:

- (void)stopTimer 
{ 
    [timer invalidate]; 
    [timer release]; 
    timer = nil; 
} 

Po wywołaniu tej metody mój zegar naprawdę przestać

1
**In .h class** 

@interface 
{ 
NSTimer * theTimer; 

} 


**in .m class** 

//put this code where you want to calling the NSTimer function 

     theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateCounter:) userInfo:nil repeats:YES]; 



- (void)updateCounter:(NSTimer *)theTimer 
{ 

    // write your code here for counter update 

} 


// put this code to Stop timer: 

    [theTimer invalidate]; 
    theTimer = nil; 
14

ten jest absolutnym rozwiązaniem.Żaden z tych powyżej pracował dla mnie, więc zrobiłem to,

gdzie chcesz, aby uruchomić stoper,

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

Metoda że rozmowy timer,

-(void)timerMethod 
{ 
    // do what you need to do 

    if (needs to be called again) { 

     [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:NO];   
    } 
} 

nadzieję, że to pomaga ,

+2

To jest jedyna rzecz, która działa dla mnie również ... – Idan

+2

Rzeczywiście ... Wygląda mi na błąd Apple. Metoda unieważniania nie działa z powodu powtarzania wartości BOOL ustawionej na szwy YES nieco dziwne dla mnie. – Plot

+2

Ten błąd nadal istnieje w iOS8. Jest to jedyny sposób na rozwiązanie problemu. – Anil

0

- (void)viewWillAppear:(BOOL)animated zostaje ponownie wywołany.

W rzeczywistości jest wywoływana za każdym razem, gdy przełączasz widoki lub po odrzuceniu widoku modalnego. Zasadniczo za każdym razem, gdy widok ponownie pojawia się na ekranie, nie tylko za pierwszym razem.

W takim przypadku licznik zostanie ponownie uruchomiony, mimo że został wcześniej unieważniony.

0

Po utworzeniu timera tylko zarejestrować go uruchomić w NSRunLoopCommonModes:

[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];

Następnie invalidate metoda zadziała.

0

Działa to dla mnie

dispatch_async(dispatch_get_main_queue(), ^{ 
    [timer invalidate]; 
}); 
1

To wystarczyły mi w Swift

override func viewWillDisappear(animated: Bool) { 
    super.viewWillDisappear(animated) 

    dispatch_async(dispatch_get_main_queue(),{ [weak self] in 

     self?.idleTimer?.invalidate() 
     self?.idleTimer = nil 

    }) 

} 
Powiązane problemy