2 - 3 ptits détails pour finaliser mon application "Brain Storming"

13»

Réponses

  • NseaProtectorNseaProtector Membre
    mars 2010 modifié #62
    Heureusement que t'es là  !!! J'adore me faire flageolet  >:) ça m'aide a mémoriser !
    Désolé prepa75 !

    Alors si tu veux tester correctement c'est plutôt ça:
    - (void)dealloc<br />{<br /><br /> if (timer !=nil) {<br />&nbsp; &nbsp; &nbsp; &nbsp; [timer invalidate];<br />&nbsp; &nbsp; &nbsp; &nbsp; [timer release];<br />&nbsp; &nbsp; &nbsp; &nbsp; timer = nil;<br />}
    


    Sinon comme le dis zoc le test est inutile car en objc-C tu peux envoyer des messages a nil.
    Merci zoc.
  • prepa75prepa75 Membre
    11:36 modifié #63
    dans 1269372611:

    Heureusement que t'es là  !!! J'adore me faire flageolet  >:) ça m'aide a mémoriser !
    Désolé prepa75 !


    ya pas de soucis  ;) ma question étais donc pas si bête que ça 

    dans 1269372611:

    Sinon comme le dis zoc le test est inutile car en objc-C tu peux envoyer des messages a nil.


    j'ai lu cette remarque plusieurs fois dans le book mais je ne la comprend pas trés bien ;
    concrètement cela signifie que l'on peut envoyer des messages a aucun destinataire c'est bien ça ??contrairement à  d'autre languages comme le C++ par ex...
  • NseaProtectorNseaProtector Membre
    11:36 modifié #64
    dans 1269375053:

    dans 1269372611:

    Sinon comme le dis zoc le test est inutile car en objc-C tu peux envoyer des messages a nil.


    j'ai lu cette remarque plusieurs fois dans le book mais je ne la comprend pas trés bien ;
    concrètement cela signifie que l'on peut envoyer des messages a aucun destinataire c'est bien ça ??contrairement à  d'autre languages comme le C++ par ex...

    Et bien, je penses qu'objc-C test si la variable contient un pointeur valide avant d'envoyer le message, du coup nous les "users" on peut faire l'économie du test et cela évite des plantages.
  • prepa75prepa75 Membre
    11:36 modifié #65
    dans 1269375602:


    Et bien, je penses qu'objc-C test si la variable contient un pointeur valide avant d'envoyer le message, du coup nous les "users" on peut faire l'économie du test et cela évite des plantages.


    ok merci , je pense avoir compris la subtilité  :P
  • prepa75prepa75 Membre
    11:36 modifié #66
    Bonsoir à  tous ,

    voici mon problème avec le timer :

    lorsque je clique sur le boutton tout va bien le décompte se fait , la barre se charge à  la bonne vitesse etc...mais lorsque je reclique sur ce boutton la barre va 2X plus vite puis 4X etc etc...

    si quelqu'un a une idée...
    -(IBAction)comparaison:(id)sender	//méthode de comparaison<br />{<br />	if(choixopp != 0)<br />		<br />	{<br />		<br />			NSLog(@&quot;Pas de timer, on le crée et on le démarre.&quot;);<br />			<br />			timer = [[NSTimer scheduledTimerWithTimeInterval:0.01<br />													&nbsp; target:self<br />													selector:@selector(timerAction:) //la méthode appeler a chaque intervalle<br />													userInfo:nil<br />													 repeats:YES] retain];<br />		<br />		count = 0;	}<br /><br />- (void)timerAction:(NSTimer *)aTimer<br />{<br />	if(count &lt; 100)<br />	{count++;<br />	printf(&quot;count : %f&quot; ,count);<br />		[progression setDoubleValue:count];<br />	}<br />	<br />}<br />
    

  • AliGatorAliGator Membre, Modérateur
    11:36 modifié #67
    Ben heu je vois pas ce qui te choque, c'est normal...
    A chaque fois que tu cliques, tu crées un timer.
    Si tu cliques 3x, tu crées 3 timers.
    Si chaque timer incrémente ta valeur de count, bah avec 3 timers tu as 3 appels à  timerAction (un pour chaque timer) à  chaque période de 0.01s. Logique, quoi ;)
  • prepa75prepa75 Membre
    11:36 modifié #68
    ah ok d'accord je comprend mais c'est pas ce que je veux...comment fait - on pour réinitialiser le compteur ? parsque je suppose que cré un compteur à prés chaque clique sur le boutton n'est pas la bonne solution  :-*

    parsque la au premier clique la barre de progression passe de 0 a 100 en 10s , au 2eme clique elle le fait en 5s etc etc...

    donc je dois juste initialiser le compteur des que l'on reclique sur le button.

    c'est bien ces lignes là ??  :
    <br /><br /> [timer invalidate];<br />&nbsp; &nbsp; &nbsp; &nbsp; [timer release];<br />&nbsp; &nbsp; &nbsp; &nbsp; timer = nil;<br /><br />
    

  • 11:36 modifié #69
    Au temps que je me souvienne, le fait d'appeler "invalidate" relâche aussi le timer !
  • prepa75prepa75 Membre
    11:36 modifié #70
    Oki donc ça devrai etre bon non ???
  • AliGatorAliGator Membre, Modérateur
    11:36 modifié #71
    Oui Louka, enfin pas tout à  fait, disons plutôt que :

    1) [NSTimer scheduledTimerWith...] crée un timer, et l'installe automatiquement sur la RunLoop dans la foulée, cette dernière se chargeant de le retenir (donc fait un retain implcite). Du coup, nous on récupère, en sortie de "scheduledTimerWithMachin", un objet qui ne nous appartient pas (on n'a pas de retain dessus, si tu préfères, pour nous il est vu comme un objet autorelease, c'est la RunLoop qui en est possesseur et qui gèrera ce timer et qui a fait le release en interne)

    2) Quand tu fais [timer invalidate], ça désinstalle ledit timer de la RunLoop (autrement dit il n'est plus programmé pour se déclencher, il va arrêter de fonctionner et d'être déclenché par la RunLoop)... et du coup ladite RunLoop le relâche (donc fait un release implicite, qui correspond à  celui fait pour "balancer" le retain implicite fait lors de l'installation du timer dans la RunLoop)

    Au final, si tu te contentes de faire "scheduledTimerWithMachin" d'un côté pour créer et démarrer le timer, alors un "invalidate" de l'autre va équilibrer les choses en arrêtant et relâchant le timer. Du coup pas besoin de release en effet.


    Mais, maintenant, beaucoup de programmeurs aiment faire un "retain" sur le timer qu'ils récupèrent de scheduledTimerWithMachin. En effet, comme expliqué plus haut, ce n'est pas indispensable quand on sait que le timer est déjà  retenu par la RunLoop tant qu'il est installé dessus. Mais c'est compréhensible de le faire quand même (et après tout, ça ne coûte rien, d'ailleurs le mécanisme de retain/release est un peu fait pour ça), dans le sens où le timer retourné est ensuite utilisé aussi par ta classe (justement pour le manipuler, lui envoyer des messages...). Donc c'est une bonne pratique, pas obligatoire mais cohérente que de faire un "retain" sur le timer pour la simple raison qu'on compte lui envoyer des messages par la suite, à  ce timer, en particulier le "invalidate".

    Et du coup évidemment, si tu fais ce "retain" supplémentaire après le "scheduledTimerWithMachin", il faut rester logique et faire un "release" après le "invalidate".
  • NseaProtectorNseaProtector Membre
    11:36 modifié #72
    Si je comprends bien dans l'exemple que je lui ai donné et du coup dans son exemple, vu que je ne fait pas de retain après le scheduled... le release n'est pas nécessaire. Si je mets un log pour récupérer le "count" il sera déjà  à  0 ! 
  • AliGatorAliGator Membre, Modérateur
    mars 2010 modifié #73
    Tout à  fait... du moins sur le principe. Sauf que je te dois de te faire des remarques sur deux points dans ta réponse, car en réalité ta phrase "Si je mets un log pour récupérer le "count" il sera déjà  à  0" me pose deux problèmes :

    1) C'est une mauvaise idée de se baser sur le retainCount bien souvent : on ne sait pas ce qui est fait en interne, ce n'est pas toujours un bon indicateur (peut-être que la RunLoop au lieu de faire un release immédiat, fait un autorelease, et donc que le retainCount sera diminué plus tard, par exemple). Donc certes, ce retainCount est le principe de base du mécanisme de reference-counting et du retain/release, mais ce n'est pas une bonne idée que de se baser dessus pour autant, vu qu'en plus il y a quelques cas alambiqués (je pense aux singletons, aux cas particulier comme NSString...)

    2) De toute façon justement si tu fais [timer invalidate] et que tu n'avais pas fait de "retain" avant, en effet du coup logiquement le retainCount va passer à  0... et du coup le timer va être détruit. Mais du coup, il ne faut surtout pas après cela faire d'autres appels de méthodes sur la variable "timer", car tu appellerais des méthodes sur un objet qui n'existe plus en mémoire. C'est d'ailleurs pour ça qu'on prend la précaution juste après de faire le [tt]timer = nil[/tt], pour éviter de risque d'envoyer des messages à  l'objet détruit.
    ...
    Donc si tu fais un "release" en trop justement, bah ça va planter...
    Mais si tu fais un log pour récupérer le retainCount comme tu le dis dans ton message... ça va pas t'afficher zéro, ça va planter aussi !! A cause de l'appel à  [timer retainCount] sur l'objet timer qui sera déjà  détruit à  ce stade !

    Au final, il est impossible d'avoir un cas où [monObjet retainCount] te retourne 0, puisque si c'est le cas (que le retainCount est tombé à  zéro), alors l'objet a justement été détruit de la mémoire... donc que tu ne peux pas appeler de méthode (retainCount comme une autre) dessus ;)


    Mais bon, à  part ça sur le principe tu as bon :P
  • NseaProtectorNseaProtector Membre
    11:36 modifié #74
    Merci Ali pour cette précision chirurgicale qui éclaire nos lanternes ! Du coup, je me demande bien comment fait Mala pour déterminer dans sa catégorie les variables non désallouées ?
    Pour mémoire http://www.pommedev.com/forum/index.php?topic=4831.msg49205#msg49205
  • AliGatorAliGator Membre, Modérateur
    11:36 modifié #75
    Bah il vérifie juste qu'on a pensé à  remettre toutes les variables à  nil.
    Ca ne veut pas dire que les variables sont correctement désallouées (rien ne t'empêche d'affecter 'nil' à  une variable d'instance dans le dealloc, sans lui envoyer le "release" qui lui est dû), ça t'indique juste les variables que tu as oublié de mettre à  'nil'.

    Le bt de sa catégorie n'est pas de vérifier que les variables d'instance sont bien désallouées avec un retainCount de 0, mais juste de vérifier qu'on a pas oublié de faire une passe sur certaines variables (genre pendant ton développement tu as rajouté une variable d'instance dans le .h de ta classe, mais tu oublies de rajouter le "release" qui va bien dans le "dealloc" existant). Pour t'inciter à  faire le release, suivi par le "=nil" immédiatement après.

    Si tu fais un "release" sans faire de "=nil", sa catégorie va te signaler le warning, puisque la variable ne sera pas nil.
    Si tu fais un "=nil", mais oublie de faire le release, sa catégorie va passer ça sous silence, puisque la variable est bien à  nil même s'il y a un leak.

    Donc sa catégorie a pour but d'inciter à  ne pas oublier de faire une passe sur chaque variable d'instance, dans la mesure où tu fais bien un "=nil" après chaque "release" que tu fais dans ton "dealloc".
    Pour ma part la plupart du temps si quand je fais un "release" sur une v.i. je ne fais un "= nil" après (ou à  défaut, une affectation à  une autre valeur valable) que quand ce release est en plein milieu de la vie de la classe, mais je le fais jamais dans le dealloc puisque ce dealloc étant appelé juste au moment de la destruction de l'objet, je sais que les variables d'instance ne seront même plus accessibles après ce dealloc (car l'objet n'existera plus) et donc qu'il n'y a en général pas de risque d'appeler des méthodes sur ces "dandling pointers". Je ne fais ce "= nil" dans le dealloc que quand il y a des considérations particulières (partage de v.i. entre threads, synchronisation d'objets, ...)
  • prepa75prepa75 Membre
    11:36 modifié #76
    Merci beaucoup Ali pour toute ces précisions , je pense avoir résolu mon problème.des que je clique sur le bouton, mon timer est réinitialisé et il repart de plus belle 

    voici mon code : ça marche mais la procédure est-elle correcte??
    <br /><br />- (void)timerAction:(NSTimer *)aTimer<br />{<br />	if(count &lt; 100)<br />	{<br />		count++;<br />	<br />		[progression setDoubleValue:count];<br />	}<br />	if(count ==100)<br />	{<br />		[timer invalidate];<br />		count = 0;<br />		printf(&quot;&#092;ncount : %f&quot; ,count);<br />	}<br />	<br />}<br /><br />if(choixopp != 0)<br />		<br />	{<br />		count = 0;<br />		[progression setDoubleValue:count];<br />			[timer invalidate];<br />			[timer release];<br />			timer = nil;<br />			NSLog(@&quot;Pas de timer, on le crée et on le démarre.&quot;);<br />			<br />			timer = [[NSTimer scheduledTimerWithTimeInterval:0.1<br />													&nbsp; target:self<br />													selector:@selector(timerAction:) //la méthode appeler a chaque intervalle<br />													userInfo:nil<br />													 repeats:YES] retain];<br />}<br /><br />
    

  • AliGatorAliGator Membre, Modérateur
    11:36 modifié #77
    Ca m'a l'air déjà  mieux.

    Petite coquille qui reste dans ton code : imagine que le temps soit écoulé (donc count atteint 100), et qu'ensuite après tu recliques sur ton bouton :
    - tu auras appelé [timer invalidate] dans le timerAction (dans le if(count==100)), mais tu ne l'auras pas releasé ni mis à  nil
    - du coup dans ton code du bouton après ton if(choixopp!=0), tu refais un "invalidate" suivi cette fois de release et de =nil.

    En soit, je suis pas sûr que ça pose problème, car à  mon avis l'appel à  "invalidate" la 2e fois n'aura aucun effet, car je suppose que dans l'implémentation qu'Apple a fait de invalidate, ils vérifient que le timer n'a pas déjà  été invalidé. Donc si c'est bien le cas, c'est pas dramatique et ça fonctionnera.

    Mais en soi quand ton count atteindra la valeur 100, tu auras toujours ton timer dans la variable "timer" (et toujours valide, puisque tu avais fait un "retain" dessus et toujours pas de "release", donc tu as toujours le droit de le manipuler sans que ça risque de crasher), sauf que ce timer sera invalidé (il aura été enlevé de la runloop et sera donc stoppé)... Du coup à  se demander si c'est très logique comme fonctionnement. Surtout que peut-être que dans ton appli à  un moment tu vas tester si (timer==nil) dans le but de savoir si timer existe et donc si un timer est lancé... alors que tu peux dans ton cas avoir un timer qui n'est pas nil, mais qui a été invalidé entre temps.

    Donc voilà , sur le principe ça fonctionne, mais ça serait sans doute plus logique de faire suite ton "invalidate" également par un "release" puis un "=nil" dans le "if(count==100)", comme tu l'as fait dans le "if(choixopp!=0)", juste pour être cohérent. Et pour te permettre si le besoin se fait un jour de pouvoir tester si un timer existe en testant si timer==nil sans risquer de tomber sur le cas où ton timer existe et n'est pas nil, mais n'est pas installé sur la runloop et donc ne se déclenchera plus.
  • prepa75prepa75 Membre
    11:36 modifié #78
    Oki merci Ali j'ai corrigé et ça marche toujours  :P
    bon je pense être apte a utiliser un timer  ;)

    merci tout le monde !!!

    Ah derniere question : concernant la libération de la ram pour ne pas surchargé cette derniere , elle se fait dans le release et l'invalidate c'est bien ça??

  • prepa75prepa75 Membre
    mars 2010 modifié #79
    Bon j'ai refait tout mon .m et bien modifié mon .h

    il reste encore des choses qui peuvent êtrent raccourcies, j'ai abandonné le tableau en C (oui je sais c'est lâche  :P)

    je vous laisse juger  ;)
  • prepa75prepa75 Membre
    11:36 modifié #80
    Euh j'ai un ptit souci avec mon programme...je l'ai passé à  un ami pour qu'il le teste et il a constaté un bug dont je ne connais pas la solution :

    lorsque le LevelIndicator défile, on laisse le click gauche de la souris enfoncé sur la barre et celle-ci se met en pause...comment pourrais-on remédier à  ce problème assez enuyeux , sachant que tout le jeu est basé sur la rapidité de calcul de l'utilisateur  :P ??
Connectez-vous ou Inscrivez-vous pour répondre.