Timer et pauses

muqaddarmuqaddar Administrateur
23:33 modifié dans API AppKit #1
Soit un timer avec repeat à  YES et un retain.
Soit une méthode.

Je souhaite faire faire une pause à  mon timer tant que quelquechose n'est pas fini d'éxécuter ds la méthode.

Je pensais faire un invalidate pour la pause, ensuite un fire pour le relancer. La pause marche mais pas le relancement, invalidate détruit le timer d'après la doc.

Je décide donc d'appeller la première méthode qui lance le timer : [self declencheTimer], ... sauf que le premier timer n'a pas été releasé... pas glop. Si je release le premier timer apr!s le invalidate, ça plante... :(

Si vous avez pas tout compris, voici un peu de code :

- (void)declencheTimer <br />{<br />timer = [[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(check:) userInfo:nil repeats:YES] retain];<br />[timer fire];<br />}


et ds la méthode qui doit stopper et relancer le timer

<br />if (comptage &lt; [newArray count]) {<br />   if ([timer isValid]==YES) {<br />     [timer invalidate];						<br />    }<br />}<br />else {<br />   	[self declencheTimer];					<br />}<br />

Réponses

  • cbrandtcbrandt Membre
    mars 2005 modifié #2
    dans ce genre de situation, j'aurais tendence à  faire un [self performSelector:wihObject:afterDelay:] à  la fin de la méthode de mon pseudo-timer...
    edit:
    ... au lieu d'utiliser un timer
  • ClicCoolClicCool Membre
    23:33 modifié #3
    dans 1111585098:

    dans ce genre de situation, j'aurais tendence à  faire un [self performSelector:wihObject:afterDelay:] à  la fin de la méthode de mon pseudo-timer...


    Merci cBrandt, je me tue à  le lui suggérer ::)
  • muqaddarmuqaddar Administrateur
    23:33 modifié #4
    Oui mais non.

    Je vois pas le rapport entre le performSelector qui ne se répète pas Hervé et mon Timer à  YES !!!
  • Eddy58Eddy58 Membre
    mars 2005 modifié #5
    A mon avis, tu dois seulement invalider le timer si les conditions ne sont pas réunies, ensuite quand tu en as besoin tu le relances. :)
    dans 1111584788:

    <br />-(void)declencheTimer <br />{<br />timer=[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(check:) userInfo:nil repeats:YES];<br />}<br />
    

    <br />if (comptage &lt; [newArray count] &amp;&amp; [timer isValid]==YES) <br />{<br />  [timer invalidate];						<br />}<br />else <br />{<br />   	[self declencheTimer];					<br />}<br />
    

  • muqaddarmuqaddar Administrateur
    23:33 modifié #6
    Oui mais il est écrit pour invalidate :

    Stops the receiver from ever firing again and removes it from any run loops.

    De plus, si j'enlève le retain, il n'est plus reconnu pour l'invalider.
  • Eddy58Eddy58 Membre
    23:33 modifié #7
    J'utilise avec succés à  peu près le même genre de code que ci-dessus pour stopper un timer et le remettre en marche quand j'en ai besoin dans une de mes applis. Et je n'utilise jamais de retain sur un timer... :)
  • muqaddarmuqaddar Administrateur
    23:33 modifié #8
    Je me prends ça Eddy : [NSCFType isValid]: selector not recognized
  • Eddy58Eddy58 Membre
    23:33 modifié #9
    Ok, apparemment la méthode isValid n'est pas reconnue, mais avec le retain elle y est c'est ça ? Un peu bizarre.... ???
    Je te propose de ruser un peu avec un bool (nommé timerState par exemple) que tu déclares dans ton fichier d'interfaçage puis : :)
    <br />-(void)declencheTimer <br />{<br />timer=[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(check:) userInfo:nil repeats:YES];<br />}<br />
    

    <br />if (comptage &lt; [newArray count] &amp;&amp; timerState==YES) <br />{<br />  timerState=NO;<br />&nbsp; [timer invalidate];<br /> }<br />else <br />{<br />&nbsp; &nbsp; &nbsp; timerState=YES;<br />   	[self declencheTimer];					<br />}<br />
    

  • ClicCoolClicCool Membre
    23:33 modifié #10
    dans 1111589303:

    Oui mais non.

    Je vois pas le rapport entre le performSelector qui ne se répète pas Hervé et mon Timer à  YES !!!


    Je te déconseille l'usage de multiples timer chacun devant tourner 16 fois puis être invalidés. ça risque de devenir le foutoir tous ces timers invalidés qui trainent encore dans ta runLoop :(
    There is no method that removes the association of a timer from an NSRunLoop"send the timer the invalidate message instead. invalidate disables the timer, so it no longer affects the NSRunLoop.


    A la place tu peux (si on en reste à  ton précédent exemple de ta méthode appelée par notification) devant boucler 16 fois avec 0.04 de pause:
    - (void)methodeNotifiée:(NSNotification*)aNotification<br />{<br />	NSMutableDictionary* mesUsersInfos = [[aNotification userInfo]&nbsp; mutableCopy];<br />	[mesUsersInfos setObject:[NSNumber nuberWithInt:1] forKey:@&quot;compteur&quot;];<br />	[self maMethodeRepetee: mesUsersInfos]; // Premier appel immédiat à  ta méthode<br />// Ou bien appel retardé si besoin<br />// [self performSelector:@selector(maMethodeRepetee:) withObject: mesUsersInfos afterDelay:0.04];<br />}
    


    - (void)maMethodeRepetee:(NSMutableDictionary*)mesUsersInfos<br />{<br />	.../... ici tu fais ta tambouille .... puis<br /><br />	NSNumber* compteur = [mesUsersInfos objectForKey:@&quot;compteur];<br />	if ( 16&gt;[compteur intValue]) {<br />		NSNumber* compteurPlusBifluore = [NSNumber nuberWithInt:([compteur intValue] +1)];<br />		[mesUsersInfos setObject:compteurPlusBifluore forKey:@&quot;compteur&quot;];<br />		[self performSelector:@selector(maMethodeRepetee:) withObject: mesUsersInfos afterDelay:0.04];<br />	}<br />}
    
  • muqaddarmuqaddar Administrateur
    23:33 modifié #11
    ouh là .

    Tu as mélangé deux sujets en même temps ClicCool.

    Les timers qui doivent se répéter 16 fois, c'est pour un autre usage que celui là  !

    Néanmoins ton exemple ici pourra m'être utile je pense.
    Merci.
  • muqaddarmuqaddar Administrateur
    mars 2005 modifié #12
    Voilà , ClicCool, je me suis servi de ta façon de faire pour remplacer mon timer par un performSelector sur mon premier problème quand je n'ai que 16 répétitions de méthodes.

    Maintenant, dans mon cas, je ne peux remplacer le timer, sa répétition étant infinie. Ou alors il faut bidouiller un truc peut-être.

    Voilà  mon code simplifié :

    [tt]- (id)init
    {
    if (self=[super init]) {
    [self performSelector: @selector(declencheMailsTimer) withObject:nil afterDelay: 2];
    }
    return self;
    }

    - (void)dealloc
    {
    [mailsTimer release];
    [super dealloc];
    }


    - (void)declencheMailsTimer
    {
    mailsTimer = [[NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(checkMails:) userInfo:nil repeats:YES] retain];
    [mailsTimer fire];
    }

    - (void)checkMails:(NSTimer*)timer
    {
    //blocage du timer
    if (comptageMails < [newMailsArray count]) {

    if ([mailsTimer isValid]==YES) [mailsTimer invalidate];

    }
    //relancer le timer
    else {
    [self performSelector: @selector(declencheMailsTimer) withObject:nil afterDelay: 2];
    }
    }[/tt]


    Le problème étant toujours le même : si je mets un release dans le dernier else sur le timer, il plante... si je ne le mets pas, j'ai une fuite mémoire, avant de le relancer. Je comprends pas pourquoi il n'est pas retenu et reconnu si je ne mets pas ce retain en haut...  :why?:
  • ClicCoolClicCool Membre
    23:33 modifié #13
    Salut Alex,

    Tu peux pas tout simplement ne pas utiliser de timer du tout ?
    (je le sens pas le coup du timer invalidé puis réactivé ...)

    Et dans le cas présent remplacer la condition
    if (16 tours)
    par:
    if (continue)
    avec un simple flag continue à  vrai ou faux ?

    Comme ça quand tu veux interrompre le processus tu mets le flag à  Faux.
    Et quand tu veux le relancer tu le mets à  Vrai et tu "amorce" en appelant la méthode une première fois.
  • ClicCoolClicCool Membre
    23:33 modifié #14
    dans 1111742453:

    Le problème étant toujours le même : si je mets un release dans le dernier else sur le timer, il plante... si je ne le mets pas, j'ai une fuite mémoire, avant de le relancer. Je comprends pas pourquoi il n'est pas retenu et reconnu si je ne mets pas ce retain en haut...  :why?:


    un Timer est retenu par la runLoop.

    Mais quand tu l'invalide rien ne garanti que la runLoop le retienne.
    Mais surtout le timer release alors son userInfo et sa cible.
    The receiver releases its references to the target and userInfo objects at this point
  • muqaddarmuqaddar Administrateur
    23:33 modifié #15
    Ok Hervé.
    Je vais essayer comme tu dis. ;)

    Tient au fait , j'ai testé ça :
    if ([mailsTimer retainCount]==1)

    mais ça a pas l'air efficace, j'ai le droit ?
  • mpergandmpergand Membre
    23:33 modifié #16
    Grilled par ClicCool et c'est normal il t'avait donné la soluce dans son post précédent !

    Vire ce timer !!

    <br />- (id)init<br />{<br />   if (self=[super init]) {   <br />      [self performSelector: @selector(checkMails) withObject:nil afterDelay: 2];      <br />   }<br />   return self;<br />}<br /><br />- (void)dealloc<br />{<br />   [super dealloc];<br />}<br /><br /><br /><br />- (void)checkMails<br />{      <br />  // vérif des nouveaux mails<br />.....<br /> // prochaine vérif dans 10 s<br />   [self performSelector: @selector(checkMails) withObject:nil afterDelay: 10];   <br />  <br />}<br /><br />
    
  • muqaddarmuqaddar Administrateur
    23:33 modifié #17
    Oui chefs ! ;-)

    Je me suis servi de sa première soluce du post précédent pour un autre endroit où je n'ai besoin que de 16 répétitions de méthodes comme dit plus haut. :)
  • muqaddarmuqaddar Administrateur
    23:33 modifié #18
    ça y est, c'est OK, ça marche sans timer.

    Belle galère (des méthodes à  rebalancer ds le thread principal), mais merci à  vous ! ;)

    alex
  • Eddy58Eddy58 Membre
    23:33 modifié #19
    Oxitan a trouvé son bonheur avec les performSelector ;), mais voici un petit projet (n'ayant plus grand chose à  voir avec celui d'Oxitan), qui, dans le principe, montre comment arrêter et redémarrer un timer. Dans le cas présent, deux timers, sur un cycle de 10 secondes :
    Le premier, mailsTimer, égrenne les 5 premières secondes, puis on le retire de la runloop, ensuite, le second, waitingTimer, est lancé, puis égrenne les 5 secondes suivantes, ensuite on le retire de la runloop, puis on relance le cycle avec mailsTimer.
    Il est vrai que la méthode isValid produit un plantage curieux, je ne sais pas pourquoi, mais je l'ai remplacé par un bool, qui ne sert pas a grand chose dans le cas actuel, mais qui est là  pour le principe également pour d'éventuels tests. :) 

    [Fichier joint supprimé par l'administrateur]
Connectez-vous ou Inscrivez-vous pour répondre.