un methode qui met en attente pendant x seconde(s)?

AnisAnis Membre
août 2013 modifié dans Apple Developer Programs #1

Bonjour  j'aimerai savoir si il existe une methode simple  (en une ligne si possible :) ) qui permet de marquer un temps de pause.


 


par exemple: 



int rebours = 10;

while (rebours != 0) {

rebours--;
//quelques lignes ici
[self methodeMagiqueQueJeRecherche:5/*secondes*/]; //donc petit temps de pause.
}

Je n'en ai pas besoin pour l'instant mais sa pourrais aider par la suite!


en effet j'ai contourner le probleme mais sans utiliser de boucle (while, for etc...)


par exemple avec cocos2d j'ai fait une fondu de son avec SimpleAudioEngine



-(void) degradeSonDown
{
double timeDown = 0.10;
musicVolume = musicVolume-0.1;

if (musicVolume > 0.0 && musicVolume <= 1.0 ) {
[[SimpleAudioEngine sharedEngine] setBackgroundMusicVolume:musicVolume];
id delay = [CCDelayTime actionWithDuration: timeDown];
id callbackAction = [CCCallFunc actionWithTarget: self selector: @selector(degradeSonDown)];
id sequence = [CCSequence actions: delay, callbackAction, nil];
[self runAction: sequence]; //sa va relancer la methode au bout de 0.10seconde

if (musicVolume==0.0)
{
musicVolume=0.0;
[[SimpleAudioEngine sharedEngine] stopBackgroundMusic];
}
}
}

Réponses

  • Salut,


     


    Regarde la documentation de NSObject sur la partie envoie de mesages. ( si j'ai bien compris ta question ;)).


  • AliGatorAliGator Membre, Modérateur
    août 2013 modifié #3
    Pour exécuter une méthode toutes les 0.10 secondes, utilise NSTimer.

    Pour exécuter un bout de code seulement après 0.10 secondes, utilise la fonction dispatch_after de GCD.

    Pour faire une animation sur des propriétés de tes vues de ton UI (changer l'alpha, la position, ... d'une UIView), utilise +[UIView animateWithDuration:animation:] et consoeurs, ou utilise CoreAnimation.
  • Donne nous le problème d'origine plutôt que ta manière de concevoir la solution, cela sera plus pratique pour qu'on puisse te donner une réponse viable.


  • Comme la dit AliGator, tu peux utilisé NSTimer pour appeler une fonction au bout d'un certain temps. Tu peux essayer :


     


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


  • AnisAnis Membre

    hmmm merci de vos réponses mais  à  vrai dire je voudrai savoir si il existe une instruction qui permettrait de faire une pause dans l'endroit ou il est mais ne pas ensuite revenir au début d'une methode (comme je sais faire avec cocos2d)!


     


    c'est pas un gros probleme c'est juste pour savoir si il y a ou y'a pas!


     


    imaginez nous somme a l'interieur d'une boucle: il y a quelques instructions  et hop une instruction, cette instruction, que je vous demande si elle existe ou pas, met un temps de pause (on va dire de 1 seconde), les 1 seconde passé, on passe a l'instruction suivante dans la boucle. 

  • Je vais peut être dire une grosse bêtise mais j'ai cru croiser une fois la fonction sleep(1); (1seconde) 


    Je ne l'ai jamais testé.


  • AliGatorAliGator Membre, Modérateur
    août 2013 modifié #8

    Je vais peut être dire une grosse bêtise mais j'ai cru croiser une fois la fonction sleep(1); (1seconde) 
    Je ne l'ai jamais testé.

    TREEESS TRESSSS mauvaise idée d'utiliser sleep() !!!
    Cela fait une pause qui bloque le thread courant. Si en plus tu fais ça sur le Main Thread, celui-ci (et donc toute l'interface de ton application) ne va plus répondre et plus rien faire pendant la durée de cette pause. Du coup si c'est une appli OSX tu vas avoir la roue multicolore, dans tous les cas comme elle ne répondra plus l'utilisateur va croire que l'application a planté, et au final cela va poser pas mal de problèmes (je n'ai pas le temps de faire tout un cours sur le Temps Réel et le MultiThreading ici, je vous laisse lire les cours spécialisés et/ou le Programming Guide Apple sur le sujet du Threading et du Concurrency Programming)
     

    hmmm merci de vos réponses mais  à  vrai dire je voudrai savoir si il existe une instruction qui permettrait de faire une pause dans l'endroit ou il est mais ne pas ensuite revenir au début d'une methode (comme je sais faire avec cocos2d)!

    Bah oui, je te l'ai déjà  citée, on fait ça avec GCD et la fonction dispatch_after.

    Sauf qu'en vrai ça ne fait pas une pause, mais ça demande d'exécuter un bout de code au bout d'un certain temps. Ainsi, si tu veux écrire l'équivalent de ce pseudo-code :
    code_before(); // du code avant
    // là  tu veux une pause de 0.1 seconde
    code_after(); // du code après
    Bah il suffit d'écrire ceci :
    code_before(); // du code avant
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
    code_after(); // ton code à  exécuter après 0.1s
    });
    Par contre si tu veux faire une boucle et attendre N secondes entre chaque itération, c'est déjà  de toute façon une mauvaise idée et il faut réfléchir autrement qu'en utilisant une boucle (par exemple pour une animation d'un paramètre il faut mieux utiliser des choses comme CADisplayLink pour synchroniser l'animation sur le rafraà®chissement de l'affichage, ou toute la panoplie d'outils mis à  disposition par CoreAnimation, etc...).



    En ce send je rejoins et suis entièrement d'accord avec yoann : ta question n'a pas vraiment de réponse car "faire une pause" dans l'exécution de ton programme n'est pas vraiment la bonne façon de faire les choses ou de poser la question. Utiliser des functions comme sleep(3) ou des méthodes comme [NSThread sleepUntilDate:] est une très mauvaise solution car bloquent ton thread, si tu as à  faire cela c'est que tu as mal pensé ton algo (que tu ne l'as pas abordé du bon bout " voir les cours sur le Temps Réel pour toutes les explications sur le sujet).

    Non, la réponse et les outils à  utiliser dépendent entièrement de ce que tu veux faire, de pourquoi à  la base tu pensais avoir besoin de "faire cette pause" dans ton code.
    - Si c'est pour une animation, ce n'est pas une pause de N millisecondes qu'il faut faire, mais CADisplayLink ou CoreAnimation ou des outils similaires qu'il faut utiliser, adaptés au besoin.
    - Si tu veux répéter du code toutes les N secondes, NSTimer.
    - Si tu veux exécuter du code après un certain temps donné, c'est GCD et dispatch_after qu'il te faut.
    - Et si tu as d'autres besoins, il y a d'autres outils (comme CFRunLoop & co) mais c'est déjà  bien plus rare d'avoir à  aller jusque-là .
    Mais en aucun cas sleep() ou [NSThread sleep]... et encore moins des hérésies comme une attente active à  coup de while() comme j'ai déjà  pu voir... (qui bouffent ton CPU " et donc ta batterie aussi, au passage, et font chauffer ton ordi ou téléphone...)


    Perso, ce que j'utilise le plus fréquemment c'est CoreAnimation (explicitement ou implicitement via les méthodes de classe de UIView dédiées à  l'animation) quand j'ai à  animer des choses, et GCD (dispatch_after mais aussi toutes les autres fonctions qu'il fournit, j'aurais du mal à  m'en passer) pour retarder l'exécution d'un bout de code à  plus tard, ou pour gérer tout ce qui est Concurrency (voir le Concurrency Programming Guide dans la doc Apple de toute façon, tu vas apprendre un paquet de choses, même si cela mérite un cours complet sur le sujet)

    Ce qu'il faut retenir c'est que faire une attente active est une très très mauvaise idée, et faire une attente passive est aussi à  éviter alors qu'il y a des outils plus adaptés. Et les outils dépendent de tes besoins, te synchroniser sur le raffraà®chissement de l'écran pour faire une animation, ou répéter du code toutes les N secondes, ou autre, ce sont des problèmes finalement bien différents. Mais penser "faire une pause dans le code" n'est pas vraiment la bonne façon d'aborder la chose.
  • D'accord merci de la (grande) précision, ça va surement mettre utile de savoir cela à  l'avenir.  :)


  • AnisAnis Membre
    août 2013 modifié #10

    merci AliGator de ta reponse et de m'avoir fait comprendre que mettre une attente dans une boucle n'est pas une bonne idée (c'est vrai, je ne savais pas que sa bouffait du CPU par exemple!). 


    Non je ne pensais surement pas appeler une fonction qui bloquerait le thread courant! je pensait plutot a une fonction qui mettrais juste un temps d'attente a son niveau (entre autre dans la boucle)  tandis que les autres methode vivaient tranquillement leurs vies, mais depuis que je sais que mettre un temps d'attente dans une boucle n'est pas une bonne idée je choisirait la methode de CoreAnimation (ou callbackAction!), qui au finale n'est pas plus mal!


     


    merci a tous de m'avoir eclairé. 


    par curiosité, savez vous dans quel cas on utilise sleep(1); ?


  • CéroceCéroce Membre, Modérateur

    par curiosité, savez vous dans quel cas on utilise sleep(1); ?

    C'est intéressant quand on fait de la programmation système. Par exemple, on affiche un message dans la console, et on veut laisser le temps à  l'utilisateur de pouvoir le lire. Pas très intéressant sous iOS, du coup.
  • Sur l'implémentation de sleep() :


    Sur un système "moderne" cette instruction va simplement placer le thread courant en file d'attente et le redémarrer lorsque le délai sera écoulé (pas de consommation de CPU donc, mais le thread courant est bloqué).


    Sur un système plus rustre, il n'est pas impossible que cette fonction soit implémentée par une boucle active (donc thread courant bloqué ET consommation de CPU).


     


    Sur l'usage de sleep() et consort tel que nanosleep() :


    Je n'en suis pas certain mais je pense que nanosleep est intensément utilisé dans iOS, mais sous le capot dans GCD, NSTimer, les animations, pour implémenter des watchdogs, ...


    Du coup pour nous simple développeur, il vaut mieux utiliser les méthodes d'attente, d'animation, ... de plus haut niveau qui sont mises à  notre disposition plutôt que d'avoir à  se repalucher toute la gestion de thread et autres joyeusetés passionnantes. C'est non seulement plus simple à  écrire mais surtout ça rend notre code moins sensible aux inévitables évolutions du système.


    Il faut considérer sleep et consort comme des fonctions de bas niveau ; lorsqu'on les utilise il faut penser à  la gestion des threads, des interruptions, ...


     


    On pouvait impunément utiliser sleep il y a quelques décennies. La programmation était mono-thread (le terme thread n'était connu que de rares initiés, les processeurs étaient mono-core). L'utilisateur d'un programme passait son temps à  attendre ; c'est le développeur qui décidait quand afficher un message, quand une saisie utilisateur était sollicitée, ... et donc c'est aussi le développeur qui devait programmer les temps d'attente éventuellement nécessaires.


    La priorité sur un système tel que iOS est l'expérience utilisateur. C'est le programme qui passe son temps à  attendre que l'utilisateur fasse quelque chose (ou plus globalement qu'il se passe quelque chose). Ce qui est recherché c'est l'immédiateté de la réponse (ou d'une réponse).


  • mpergandmpergand Membre
    août 2013 modifié #13


    par curiosité, savez vous dans quel cas on utilise sleep(1); ?




     


    Dans les threads secondaires.


    Si le thread n'a rien a faire, il va mouliner à  fond dans la boucle et pomper 100% d'un core pour lui tout seul !


     


    Donc il faut mettre une attente dans la boucle genre nanosleep(1000)


    On peut aussi utiliser sleepForTimeInterval: de NSThread qui doit faire exactement la même chose.


     


    Pour en revenir à  la question initiale: existe-t-il une méthode pour faire une pause de x seconde, la réponse est oui:



    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow: x ]];

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