2009-06-23 9 views
22

J'ai un temporisateur qui se déclenche lorsque la méthode viewWillAppear est appelée et invalide lorsque la méthode viewDidDisappear est appelée. Mais après un certain nombre de commutations entre les vues, la minuterie continue de fonctionner même après son invalidation. Quel est le problème?NSTimer n'arrête pas

Voici mon code:

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

Répondre

37

J'aurais dû garder un lien vers le minuteur en le conservant. :) J'ai posé cette question il y a 5 mois, et c'est incroyable, combien d'expérience j'ai acquise. :)

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

Comment faire cela dans ARC quand 'retain' et' release' ne sont pas autorisés? –

+1

Pour iOS 7/8, voir la réponse ci-dessous à propos de l'utilisation d'une paire de temporisations 'répétitions: NON '. –

0

Vous avez oublié de libérer la minuterie dans viewWillDisappear:

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

Cela ne devrait pas provoquer la minuterie pour continuer à tirer si ...

+1

Dans cette application de cas écrasements car l'horloge est déjà libéré. –

+0

Ben Gotow a la bonne réponse ici. Vous devez conserver le minuteur après sa création, puis l'invalider et le relâcher quand vous voulez qu'il arrête de vous rappeler – rpetrich

+0

Vous ne devez pas/devez le conserver, car la boucle d'exécution le fera, mais c'est une bonne idée si tu veux être en sécurité. – Wevah

0

De invalidate le doco dit

"La boucle d'exécution supprime et libère le temporisateur, soit juste avant le retour de la méthode invalidate, soit ultérieurement."

Je suppose que le vôtre est retiré plus tard.

6

Une méthode appelée par une minuterie doit avoir la définition

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

De cette façon, la méthode a l'instance de minuterie qui a été tiré. La façon dont vous le faites, la méthode ne saura pas si la minuterie a été invalidée ou non.

Essayez de changer l'initialisation de la minuterie pour

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

et la méthode pour

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

espoir qui aide

+0

Cela n'aura aucun effet. – rpetrich

+0

@rpetrich Si vous pouvez donner encore moins d'informations dans votre réponse ce serait super mec! –

+1

Invalider l'objet timer dans la méthode et le rendre nul. Assurez-vous également que NSTimer est déclaré en tant que propriété retain. Cela fonctionne pour moi. –

2

Cela peut ne pas être la question, mais vous devez conserver la référence à temporisateur renvoyé par scheduledTimerWithInterval :. Sans cela, votre pointeur sur la minuterie peut être invalide au moment où vous allez l'arrêter.

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

Également, essayez de définir un point d'arrêt dans viewDidDisappear et assurez-vous qu'il est appelé!

0

J'ai eu le même problème.

Je ne peux pas dealloc mon exemple, si la minuterie est toujours en cours, donc je dois l'arrêter avant d'appeler:

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

Après avoir appelé cette méthode ma minuterie vraiment arrêter

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

Cette est une solution absolue.Aucun de ceux ci-dessus a travaillé pour moi, donc je l'ai fait,

où vous voulez commencer la minuterie,

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

La méthode que les appels de la minuterie,

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

this helps

+2

C'est la seule chose qui fonctionne pour moi aussi ... – Idan

+2

En effet ... Ça me semble un bug Apple. La méthode invalider ne fonctionne pas en raison de la valeur de BOOL de répétition définie sur YES semble un peu étrange pour moi – Plot

+2

Ce bug existe toujours dans iOS8. C'est le seul moyen de résoudre le problème. – Anil

0

- (void)viewWillAppear:(BOOL)animated est appelée à nouveau. En fait, il est appelé chaque fois que vous changez de vue ou après avoir rejeté une vue modale. Fondamentalement, chaque fois que votre vue réapparaît à l'écran, pas seulement la première fois.

Dans ce cas, la minuterie est redémarrée, même si elle a été invalidée auparavant.

0

Après avoir créé votre minuterie simplement l'enregistrer pour exécuter dans NSRunLoopCommonModes:

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

Ensuite invalidate méthode fonctionne.

0

Cela fonctionne pour moi

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

Cela m'a fait l'affaire Swift

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

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

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

    }) 

} 
Questions connexes