2009-10-17 4 views
7

J'ai un NSTimer qui se déclenche avec un intervalle de 3 secondes pour diminuer une valeur. Lorsque je fais une action qui augmente cette valeur, je veux redémarrer la minuterie pour compter 3 secondes à partir de ce point. Par exemple, si j'augmente la valeur et que la minuterie se déclenche dans 1 seconde, je veux changer cela et déclencher la minuterie en 3 secondes à la place. Puis-je invalider le minuteur et le créer à nouveau? Ou puis-je le faire avec setFireDate:, en utilisant la date actuelle et en ajoutant un intervalle de 3 secondes?Réinitialiser le temps de tir d'un NSTimer à partir de maintenant au lieu du dernier tir

+0

Enfin j'utilise setFireWithDate, quand j'augmente la valeur, j'envoie aussi un message au timer avec la date du jour plus trois secondes. Cela fonctionne ^^ Merci beaucoup. – emenegro

Répondre

7

Oui, vous pouvez l'invalider. Et créez-le à nouveau.

Vous pouvez également utiliser:

- (void) myTimedTask { 
    // other stuff this task needs to do 

    // change the variable varyingDelay to be 1s or 3s or... This can be an instance variable or global that is changed by other parts of your app 
    // weStillWantTimer is also a similar variable that your app uses to stop this recurring task 

if (weStillWantTimer) 
     [self performSelector:@selector(myTimedTask:) withObject:gameColor afterDelay:varyingDelay]; 

} 

Vous appelez myTimedTask pour démarrer la tâche récurrente. Une fois qu'il est démarré, vous pouvez changer le délai avec varyDelay ou l'arrêter avec weStillWantTimer.

+0

+1, mais certainement pas un * global *, non? :) – zoul

+0

@zoul, dépend de comment vous voulez être désordonné :-) – mahboudz

1

Invalide la minuterie et recrée-la. Cependant, assurez-vous que vous n'invalidez pas et relâchez la minuterie sauf si vous en êtes sûr car la boucle d'exécution conserve les minuteurs jusqu'à ce qu'ils soient invalidés, puis les libère elle-même. À mon avis, mixer -performSelector code avec le code timer mène à l'exécution multiple des méthodes cibles, donc je resterais loin de ça.

1

Oui, invalider et recréer la minuterie fonctionnera. C'est essentiellement ce que vous voulez faire si vous n'augmentez pas votre valeur: réinitialisez et recommencez.

1

Les setFireDate: docs mentionnent que le changement de la date d'incendie est relativement coûteux, ce qui suggère qu'il pourrait être préférable de détruire et de recréer la minuterie à moins que vous faites si beaucoup. Par souci d'argumentation, cependant, j'ai attisé cette catégorie il y a un petit moment. Je préfère cela parce qu'il encapsule le comportement d'ajustement de la date; la minuterie elle-même le gère, plutôt que son propriétaire/contrôleur. Je n'ai pas de données sur la performance à ce sujet, cependant.

@implementation NSTimer (WSSAdjustingFireDate) 

- (void)WSSFireAdjustingFireDate 
{ 
    [self fire]; 

    [self WSSSkipNextFireAdjustingFireDate]; 
} 

- (void)WSSSkipNextFireAdjustingFireDate 
{ 
    CFRunLoopTimerRef cfSelf = (__bridge CFRunLoopTimerRef)self; 
    CFTimeInterval delay = CFRunLoopTimerGetInterval(cfSelf); 
    CFRunLoopTimerSetNextFireDate(cfSelf, CFAbsoluteTimeGetCurrent() + delay); 
} 

@end 

Je l'ai utilisé les fonctions de base de la Fondation juste pour éviter de créer un NSDate. Optimisation prématurée? S'il te plaît, passe le sel.

3

J'ai fait un peu de test, et il s'avère que la réinitialisation du fireDate est environ quatre fois plus rapide que l'invalidation et la recréation du timer. Tout d'abord, je crée une minuterie qui appelle la méthode DoNothing:

if (!testTimer) { 
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0 
                 target:self 
                selector:@selector(doNothing:) 
                userInfo:nil 
                repeats:NO]; 
    testTimer = timer; 
} 

Voici le code de test:

- (void) testInvalidatingTimer { 
    for (int n = 0; n < 10000; n++) { 
     [testTimer invalidate]; 
     testTimer = nil; 

     NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0 
                  target:self 
                 selector:@selector(doNothing:) 
                 userInfo:nil 
                 repeats:NO]; 
     testTimer = timer; 
    } 
} 

- (void) testResettingTimer { 
    for (int n = 0; n < 10000; n++) { 
     if ([testTimer isValid]) { 
      testTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:3.0]; 
     } 
    } 
} 

Course à un iPad Air cède 0.198173 s pour invalidatingTimer et 0.044207 s pour resettingTimer. Si la performance est votre cible, je recommande de réinitialiser le fireDate. C'est aussi un peu moins d'effort de codage.

Questions connexes