Créer un Compte a rebour en seconde

Babyfoot34Babyfoot34 Membre
16:54 modifié dans API AppKit #1
Rebonjour a tous, voila j'ai trouver, sur les exemples de code Apple, comment créer un comteur de temps qui fonctionne tres tres bien. Sauf que voila, j'ai pas tout compris. Je souhaiterai le meme principe mais a l'envers. cad de descendre 25 a 0.

Voici le code du compteur de temps :
<br />// Le header<br />IBOutlet UILabel *callTimerLabel;<br />	NSTimer *callTimer;<br />	NSTimeInterval startTime;<br /><br />//Le m<br /><br />- (void) updateElapsedTime:(NSTimer *) timer<br />{<br />	int hour, minute, second;<br />	NSTimeInterval elapsedTime = [NSDate timeIntervalSinceReferenceDate] - startTime;<br />	hour = elapsedTime / 3600;<br />	minute = (elapsedTime - hour * 3600) / 60;<br />	second = (elapsedTime - hour * 3600 - minute * 60);<br />	callTimerLabel.text = [NSString stringWithFormat:@&quot;%02d:%02d&quot;, minute, second];<br />}<br /><br />// Initialisation du l&#39;horloge	<br />	if (nil == callTimer) {<br />		callTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self<br />						selector:@selector(updateElapsedTime:) userInfo:nil repeats:YES] retain];<br />&nbsp; &nbsp; &nbsp; &nbsp; startTime = [NSDate timeIntervalSinceReferenceDate];<br />	}<br /><br /><br />

Réponses

  • devulderdevulder Membre
    septembre 2010 modifié #2
    dans 1285745029:

    Rebonjour a tous, voila j'ai trouver, sur les exemples de code Apple, comment créer un comteur de temps qui fonctionne tres tres bien. Sauf que voila, j'ai pas tout compris. Je souhaiterai le meme principe mais a l'envers. cad de descendre 25 a 0.

    Voici le code du compteur de temps :
    <br />// Le header<br />IBOutlet UILabel *callTimerLabel;<br />	NSTimer *callTimer;<br />	NSTimeInterval startTime;<br /><br />//Le m<br /><br />- (void) updateElapsedTime:(NSTimer *) timer<br />{<br />	int hour, minute, second;<br />	NSTimeInterval elapsedTime = [NSDate timeIntervalSinceReferenceDate] - startTime;<br />	hour = elapsedTime / 3600;<br />	minute = (elapsedTime - hour * 3600) / 60;<br />	second = (elapsedTime - hour * 3600 - minute * 60);<br />	callTimerLabel.text = [NSString stringWithFormat:@&quot;%02d:%02d&quot;, minute, second];<br />}<br /><br />// Initialisation du l&#39;horloge	<br />	if (nil == callTimer) {<br />		callTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self<br />						selector:@selector(updateElapsedTime:) userInfo:nil repeats:YES] retain];<br />&nbsp; &nbsp; &nbsp; &nbsp; startTime = [NSDate timeIntervalSinceReferenceDate];<br />	}<br /><br /><br />
    



    Bonjour,

    Tu rajoutes une variable globale type int CompteurGlobal;

    Tu met la valeur a 25

    if (nil == callTimer) {
    CompteurGlobal = 25;

    Puis dans ta routine updateElapsedTime tu décrémente cette variable a chaque appel puis tu arrête le timer

    quand elle atteint zéro.

    - (void) updateElapsedTime:(NSTimer *) timer
    {
    int hour, minute, second;
      NSTimeInterval elapsedTime = [NSDate timeIntervalSinceReferenceDate] - startTime;

      CompteurGlobal--;

      if (CompteurGlobal == 0)
      {
        [timer invalidate]; // arrêt du timer aprés a toi de voir si tu détruit le timer ou pas

        return;
    }

      hour = elapsedTime / 3600;
      minute = (elapsedTime - hour * 3600) / 60;
      second = (elapsedTime - hour * 3600 - minute * 60);
      callTimerLabel.text = [NSString stringWithFormat:@%02d:%02d, minute, second];
    }

    Pas tester, mais bon cela devrait marcher ! :)

  • mpergandmpergand Membre
    16:54 modifié #3
    Pas besoin de timer:
    <br />int compteur;<br />...<br /><br />// démarrage<br />compeur=25;<br />[self performSelector:@selector(decrementeCompteur) withObject:nil afterDelay:1.0];<br /><br />// <br /><br />-(void) decrementeCompteur<br />{<br />	compteur--;<br /><br />	if(compteur&gt;0)<br />		[self performSelector:@selector(decrementeCompteur) withObject:nil afterDelay:1.0];<br />}<br /><br />
    

  • devulderdevulder Membre
    16:54 modifié #4
    dans 1285746442:

    Pas besoin de timer:
    <br />int compteur;<br />...<br /><br />// démarrage<br />compeur=25;<br />[self performSelector:@selector(decrementeCompteur) withObject:nil afterDelay:1.0];<br /><br />// <br /><br />-(void) decrementeCompteur<br />{<br />	compteur--;<br /><br />	if(compteur&gt;0)<br />		[self performSelector:@selector(decrementeCompteur) withObject:nil afterDelay:1.0];<br />}<br /><br />
    



    Normalement avec l'option repeats:YES la méthode est appeler automatiquement  tous les secondes ?

  • AliGatorAliGator Membre, Modérateur
    16:54 modifié #5
    dans 1285745753:

    Tu rajoutes une variable globale
    Ahhhh, hérésie !!! Vade retro satanas !!!

    Les variables globales sont à  éviter au maximum (pour de multiples raisons, tant en terme de pattern qu'en terme de pratique pour les effets de bords que ça peut engendrer sur des accès multiples (pour du multithread) ou le fait que c'est aucunement protégé contre un appel extérieur, et pas POO (principe de segmentation).

    Une variable d'instance est toute indiquée pour ce cas plutôt.
  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #6
    Desole mpergand mais ce code ne fonctionne pas

    Comment je fait pour afficher le decompte dans ma vue ? je n'ai pas de variable pour passer le traitement
  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #7
    Bon j'ai compris, il fonctionne le code mais le probleme est que lorsque le compte a rebour commence (par exemple a 8) et que l'utilisateur clique sur mon bouton pour répondre a la question qui lui a été posée, a ce moment la, le compte a rebour est a 4 par exemple, une autre question se présente et je remet le compte a rebour a 8, mais il defile beaucoup plus vite.

    Quelqu 'un c'est il pourquoi mon compte a rebour panique a la 2eme remise a 0 ?
    <br />-(void)decompte{<br />	compteur--;<br />	if (compteur&gt;0) {<br />		[self performSelector:@selector(decompte) withObject:nil afterDelay:1.0];<br />		leTemps.text = [NSString stringWithFormat:@&quot;%i&quot;,compteur];<br />	}<br />	else{<br />		leTemps.text = [NSString stringWithFormat:@&quot;0&quot;];<br />	}<br />	<br />	NSLog(@&quot;compteur devompte : %i&quot;,compteur);<br />} <br /><br />compteur = 8;<br />[self decompte];<br /><br />
    
  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #8
    A j'ai oublier de preciser que la 2 eme remise a 0 est lancée par le bouyon <Question Suivante>.

    <br />-(IBAction)btQsuiv:(id)sender{<br />	<br />	if (Niveau==1) {<br />		compteur=8;<br />	}<br />	else {<br />		if (Niveau==2) {<br />			compteur=6;<br />		}<br />		else {<br />			compteur=4;<br />		}<br /><br />	}<br /><br />	[self decompte];<br /><br />
    
  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #9
    :p Excusez moi je voulais dire le bouton  ;D et pas le bouyon  o:)
  • mpergandmpergand Membre
    septembre 2010 modifié #10
    il faut annuler le performSelector en cours:
    [self cancelPerformSelector:@selector(decompte) target:self argument:nil];

    et le else if ça existe  ;)
    <br />if (Niveau==1) <br />	compteur=8;<br />else if (Niveau==2) <br />	compteur=6;<br />else <br />	compteur=4;<br />	<br />
    
  • AliGatorAliGator Membre, Modérateur
    16:54 modifié #11
    Ou  [tt]compteur = 10-2*Niveau[/tt] aussi quitte à  compresser le tout en une ligne :D (et en supposant que tu n'as que 3 niveaux 1,2 et 3)
  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #12
    Excuse moi Aligator, Je n'ai pas compris ta remarque. Je n'ai que trois niveaux de difficultés et je suis tres interessé par ton code qui me ferait gagner beaucoup de place.

  • mpergandmpergand Membre
    septembre 2010 modifié #13
    Pour gérer 3 niveaux le if else ça va encore  :D
    <br />compteur=4; // niveau 3<br /><br />if(Niveau==1)<br />&nbsp; compteur=8;<br />else if(Niveau==2)<br />&nbsp; compteur=6;<br />
    


    Mais comme l'écart entre les niveaux est constant, on peut le calculer:
    compteur=8-(Niveau-1)*2;

    On peut aussi utiliser un tableau C:
    <br />static const Compteurs[3]={8,6,4};<br /><br />....<br /><br />compteur=Compteurs[Niveau-1];<br />
    

  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #14
    Hou la la, alors la je viens d'apprendre un super truc.

    Merci a tous les deux pour ces présisions

    Je vais tester et appliquer cela immédiatement.
  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #15
    Bon, Je n'arrive pas a annuler le performSelector en cours. le warning

    'Quiz' may not respond to '-cancelPerformSelector:target:argument:'

    Mon code est placé dans le bouton qui permet de changer de question. Donc le code qui annule le performSelector je l'ai placé en haut.
    Ensuite je vais chercher ma qustion et mes réponses possibles et je relance le performSelector.

    Puis-je avoir l'annulation et la relance dans la meme action (le bouton) ?
    <br />-(IBAction)btQsuiv:(id)sender{<br />	<br />	[self cancelPerformSelector:@selector(decompte) target:self argument:nil];<br />	<br />	if (Niveau==1) <br />		compteur=12;<br />	else if (Niveau==2) <br />		compteur=8;<br />	else <br />		compteur=4;<br />	<br />	<br />	indexduMot = indexduMot + 1;<br />	dict = [tabloData objectAtIndex:(indexduMot)];//On passe au Mot suivant<br /><br />	[self envoidesData];//On envoi les donnés a la vue	<br />	[self decompte];<br />	<br />	if (indexduMot==25) {<br />		NSLog(@&quot;Bravo ! Vous avez terminez ce niveau avec un score de %i.&quot;, leScoreQuiz);<br />	}<br />}<br /><br />
    



  • mpergandmpergand Membre
    16:54 modifié #16
    Oui, erreur de ma part, c'est une méthode de classe, donc il faut faire:
    [[self class] cancelPerformSelector:@selector(decompte) target:self argument:nil];
  • Babyfoot34Babyfoot34 Membre
    16:54 modifié #17
    Bon apparement il y a toujours un chti probleme car maintenant j'ai le warning suivant

    warning: no '+cancelPerformSelector:target:argument:' method found
    warning: (Messages without a matching method signature

  • AliGatorAliGator Membre, Modérateur
    16:54 modifié #18
    La solution se trouve (comme toujours ou presque) dans la doc (pour ton cas la doc de NSObject puisque "performSelector:..." & co sont des méthodes de cette classe.

    Il suffit d'utiliser la bonne méthode, avec le bon nom qui existe (mpergand t'as sans doute cité la méthode de tête, mais à  toi d'aller vérifier dans la doc quand tu vois qu'il a pas dû donner le nom exact pile poil et t'as juste donné l'idée générale). Même si tu ne connais pas l'existence de cette méthode il suffit d'aller voir dans la doc de "performSelector:withObject:afterDelay:" (que tu utilises plus haut dans ton code et qui est justement ce que tu veux annuler) qui t'explique tout ça (comment annuler, etc)
  • mpergandmpergand Membre
    16:54 modifié #19
    ah! ouais je patauge grave  :D

    - (void)cancelPerformSelector:(SEL)aSelector target:(id)target argument:(id)anArgument
    est une méthode de NSRunLoop, donc il faut faire:

    [[NSRunLoop currentRunLoop] cancel....]

    Pour NSObject la méthode s'appelle cancelPrevious...

    cancelPreviousPerformRequestsWithTarget:
    Cancels perform requests previously registered with the performSelector:withObject:afterDelay: instance method.

    + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget



    RTFM as usual  ;)

Connectez-vous ou Inscrivez-vous pour répondre.