2009-06-23 15 views
22

Ho un timer che si attiva quando il metodo viewWillAppear viene chiamato e invalida quando viene chiamato il metodo viewDidDisappear. Ma dopo una certa quantità di commutazione tra le visualizzazioni, il timer continua a sparare anche dopo che è stato invalidato. Qual è il problema?NSTimer non si ferma

Ecco il mio codice:

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"); 
} 

risposta

37

Avrei dovuto mantenere un collegamento al timer mantenendolo. :) Ho fatto questa domanda 5 mesi fa, ed è sorprendente, quanta più esperienza ho acquisito. :)

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

Come fare questo in ARC quando 'retain' e' release' non sono consentiti? –

+1

Per iOS 7/8, vedere la risposta sotto sull'uso di un paio di ripetizioni ': NO'. –

0

Hai dimenticato di rilasciare il timer in viewWillDisappear:

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

Questo non dovrebbe causare il timer per continuare a sparare anche se ...

+1

in questo caso app schiaccia perché il timer è già stato rilasciato. –

+0

Ben Gotow ha la risposta giusta qui. È necessario mantenere il timer dopo la sua creazione, quindi invalidarlo e rilasciarlo quando si desidera che smetta di richiamare – rpetrich

+0

Non lo si/ha/per mantenerlo, poiché il ciclo di esecuzione lo farà, ma è una buona idea se vuoi essere al sicuro. – Wevah

0

di invalidate il doco dice

"Il ciclo di esecuzione rimuove e rilascia il timer, appena prima che il metodo invalidi ritorni o in un momento successivo."

Suppongo che il tuo venga rimosso in un secondo momento.

6

un metodo chiamato da un timer dovrebbe avere la definizione

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

In questo modo il metodo ha l'istanza di temporizzatore che è stato licenziato. Nel modo in cui lo stai facendo, il metodo non saprà se il timer è stato invalidato o meno.

provare a modificare le inizializzazione timer per

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

e il metodo per

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

Speranza che aiuta

+0

Questo non ha alcun effetto. – rpetrich

+0

@rpetrich Se puoi dare ancora meno informazioni nella tua risposta sarebbe un ottimo amico! –

+1

Invalidate l'oggetto timer nel metodo e impostatelo a zero. Assicurarsi inoltre che NSTimer sia dichiarato come proprietà di conservazione. Questo funziona per me. –

2

questo potrebbe non essere il problema, ma è necessario mantenere il riferimento alla timer che viene restituito da scheduledTimerWithInterval :. Senza fare ciò, il tuo puntatore al timer potrebbe non essere valido al momento del tuo arresto.

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

Inoltre, provare ad impostare un punto di interruzione in viewDidDisappear e assicurarsi che sia sempre chiamato!

0

Ho avuto lo stesso problema.

Non posso dealloc il mio esempio se il timer è ancora in esecuzione, quindi devo fermarla prima di chiamare:

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

Dopo aver chiamato questo metodo il mio timer davvero fermare

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

Questo è una soluzione assoluta.Nessuno di quelli sopra ha funzionato per me, così ho fatto questo,

in cui si desidera avviare il timer,

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

Il metodo che le chiamate 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];   
    } 
} 

Spero che questo aiuti ,

+2

Questa è l'unica cosa che funziona anche per me ... – Idan

+2

In effetti ... Sembra un bug di Apple per me. Il metodo invalido non funziona a causa del valore BOOL di ripetizione impostato su SÌ si presenta un po 'strano per me – Plot

+2

Questo bug esiste ancora in iOS8. Questo è l'unico modo per risolvere il problema. – Anil

0

- (void)viewWillAppear:(BOOL)animated viene chiamato di nuovo.

Infatti viene chiamato ogni volta che si cambia visualizzazione o dopo aver chiuso una vista modale. In pratica ogni volta che la tua vista riappare sullo schermo, non solo la prima volta.

Quindi in questo caso il timer viene riavviato, anche se prima è stato invalidato.

0

Dopo aver creato il vostro timer solo registrare il suo funzionamento in NSRunLoopCommonModes:

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

Poi invalidate metodo funziona.

0

questo funziona per me

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

Questo ha fatto il trucco a me in Swift

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

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

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

    }) 

}