stringByAppendingString: plantage de l'app

tet2bricktet2brick Membre
21:06 modifié dans API UIKit #1
Re-bonjour! :D

Je reviens assez rapidement suite à  un autre problème, dans ma petite app de test, j'essaie de concaténer deux strings dans une seule variable et ensuite de l'afficher dans un label.

Jusqu'à  maintenant l'affichage dans le label de n'importe quel variable contenant une string n'a pas posé de problème, par exemple:

message=[[NSString alloc] initWithFormat:@&quot;Hello world!&quot;];<br />labelmsg.text=message;<br />


Aucun problème, le texte s'affiche bien dans le label, mais si je fait ceci:

message=[[NSString alloc] initWithFormat:@&quot;Hello world!&quot;];<br />message=[message stringByAppendingString:@&quot;et le monde lui répondit merde&quot;];<br />labelmsg.text=message;


Le simulateur iphone se bloque.

Si vous pouvez m'aider...  :why?:

Réponses

  • CeetixCeetix Membre
    21:06 modifié #2
    Pourquo tu fais du initWithFormat et pas plutôt du initWithString ?
  • tet2bricktet2brick Membre
    21:06 modifié #3
    dans 1237555860:

    Pourquo tu fais du initWithFormat et pas plutôt du initWithString ?


    En fait c'est dans un if et les autres possibilités ont le texte contenant les variables entrées par l'utilisateur
  • CéroceCéroce Membre, Modérateur
    mars 2009 modifié #4
    Tes questions sont basiques, c'est normal de se les poser, mais tu ferais mieux de t'acheter un bon bouquin (celui-ci est pour le Mac, mais c'est très proche, et je ne suis pas sûr qu'il existe aussi bien pour l'iPhone).

    Ton code pose problème:
    -[NSString stringByAppendingString] renvoie une nouvelle chaà®ne. La première reste donc en mémoire sans être jamais désallouée. Par contre, je ne comprends pas pourquoi ça plante.

    (Et Ceetix a raison, c'est bizarre d'utiliser initWithFormat:, quand on ne lui passe pas une chaà®ne de formattage).
  • tet2bricktet2brick Membre
    21:06 modifié #5
    Merci beaucoup Céroce pour la référence du livre, c'est un peu chaud financièrement actuellement, mais à  mon avis je vais l'acheter (oué oué même 37€ ça peut faire mal lors de fin de mois serrées  :) )

    Je manque clairement de bases, la j'essaie de me les faire par moi même en attendant ^^

    Maintenant j'utilise initWithString pour la chaine ne devant pas contenir de variables, ça fonctionne tout aussi bien, donc je me coucherais moins bête.

    Au sujet du problème précis, tu dis que la première reste en mémoire, mais à  part le fait que ça ne soit pas super optimisé ça ne devrait pas faire planter, si?

    A coté de ça si je ne fait que concaténer les strings sans les afficher dans le label tout fonctionne, c'est lorsque je lui passe la variable message que ça plante.

    Merci de votre aide en tout cas, je patauge un peu, mais je vais y arriver ^^
  • CeetixCeetix Membre
    21:06 modifié #6
    Si ça peut planter ^^.
    Essaie avec NSMutableString
  • CéroceCéroce Membre, Modérateur
    mars 2009 modifié #7
    dans 1237560655:

    A coté de ça si je ne fait que concaténer les strings sans les afficher dans le label tout fonctionne, c'est lorsque je lui passe la variable message que ça plante.


    Est-ce vraiment sur labelMsg.text = message; que ça plante ?
    À vérifier au débogueur.

    Comme la nouvelle chaà®ne renvoyée par -[NSString stringByAppendingString:] est autoreleasée, elle sera libérée à  la fin du cycle du runtime et message ne pointera plus sur rien.
  • tet2bricktet2brick Membre
    21:06 modifié #8
    La j'avoue que je suis perdu, pas vraiment l'habitude d'utiliser le débogueur, il va falloir que je me penche dessus.

    Le cycle du runtime? c'est à  dire?
    Au plus j'en apprend au plus je me rend compte de mon ignorance  :)

    Et vu que j'ai en général plus de facilité en commençant par la pratique et en apprenant le reste sur le tas, c'est un peu dur vu que les tutoriels bien fait pour l'objective-c sont un peu moins courant que pour les autres langages ^^

    Sinon au final j'ai fait ça:

    message=[[NSString alloc] initWithFormat:@&quot;Hello world!&quot;];<br />message2=@&quot;et le monde lui répondit merde&quot;;<br />message=[[NSString alloc] initWithFormat:@&quot;%@ %@&quot;, message, message2];<br />labelmsg.text=message;
    


    Ca fonctionne nickel, mais je ne sais pas si c'est "propre"
  • GreensourceGreensource Membre
    21:06 modifié #9
    En effet ce n'est pas "propre" ^^
    Enfin disons que appendWithString est fait pour ça donc tu devrais l'utiliser.

    J'ai essayer ton code chez moi il passe sans souci, je pense que ça viens d'ailleurs (c'est comme la vérité ^^)

    Mais quand bien même, il y a quand même un problème de fuite de mémoire.
    J'ai donc plutôt essayer ceci:
         &nbsp;  NSString* message=[[NSString alloc] initWithString:@&quot;Hello world!&quot;];<br />	NSString* final;<br />	final = [message stringByAppendingString:@&quot;et le monde lui répondit merde&quot;];<br />	// On supprime le message initial<br />	[message release];<br />	// On affiche le message final<br />	NSLog(final);<br />	// On vérifie que le message initial est bien relaché (dois afficher null)<br />	NSLog(message);<br />	// Finallement on relâche le message final<br />	[final release];<br />	NSLog(final);
    

    Sauf que les NSString* reste en mémoire! C'est délire, elle s'affiche quand bien même j'ai fait un release dessus! Si quelqu'un comprends...
  • FloFlo Membre
    mars 2009 modifié #10
    <br />message=[[NSString alloc] initWithFormat:@&quot;Hello world!&quot;];<br />message2=@&quot;et le monde lui répondit merde&quot;;<br />message=[[NSString alloc] initWithFormat:@&quot;%@ %@&quot;, message, message2];<br />labelmsg.text=message;<br />
    


    ça marche, mais si je ne m'abuse, tu as une belle fuite mémoire sur le premier message.
    En gros la variable message référence un objet NSString initialisé avec  @Hello world. Or lorsque tu fais la ligne suivante :

    <br />message=[[NSString alloc] initWithFormat:@&quot;%@ %@&quot;, message, message2];<br />
    


    message ne référence plus @Hello World mais un nouvel object NSString étant la recopie de message et de message2.
    ça ne plante pas mais le premier @Hello world risque de rester dans la mémoire "ad vitam eternam" à  moins que tu n'utilise le ramasse miettes...

    [EDIT] oups grilled... par un gars de l'IFSIC en plus... ;-)
  • FloFlo Membre
    21:06 modifié #11

    Sauf que les NSString* reste en mémoire! C'est délire, elle s'affiche quand bien même j'ai fait un release dessus! Si quelqu'un comprends...


    Il me semble que quand tu fais un release sur une variable, elle n'est pas détruite immédiatement, de plus si tu ne fais pas message = nil ou final = nil l'adresse reste dans la variable qui ne sera détruite qu'à  la fin de la procédure.
  • schlumschlum Membre
    21:06 modifié #12
    Encore une fois, quel rapport avec l'iPhone SDK ?  ???

    Il y a un forum " Débutants : les bases d'Objective-C & Cocoa "
  • CeetixCeetix Membre
    21:06 modifié #13
    Ah GreenSource j'aime voir ce code ^^
  • AliGatorAliGator Membre, Modérateur
    21:06 modifié #14
    NSString est un class cluster et en plus ici on travaille avec des chaà®nes constantes (@blablabla), donc c'est pas forcément le meilleur exemple pour essayer de comprendre pourquoi les chaà®nes sont pas relâchées ou sont encore en mémoire etc car il y a des cas un peu particulier sur les chaà®nes constantes & co.

    De plus, appeler "release" sur une variable NE met PAS cette variable à  nil ! Cela détruit la variable (enfin l'objet sur lequel elle pointe plus exactement), du moins si personne d'autre n'a fait un retain dessus entre temps, mais la variable ne pointe pas sur nil après cela, elle pointe toujours sur le même espace mémoire, c'est juste que du coup cet espace mémoire n'est plus valide après ça.

    Toto* t = [[Toto alloc] init]; // la variable t pointe vers l&#39;endroit de la mémoire où est stocké l&#39;objet Toto ainsi créé<br />[t release]; // on détruit l&#39;objet Toto<br />// ...<br />NSLog(@&quot;t = %@&quot; , t); // ne va pas afficher nil, voire même va sans doute planter
    
    Avec cet exemple de code ça va sans doute planter car va essayer d'accéder à  l'objet qui est à  l'adresse mémoire pointée par la variable t, mais autant avant il y avait l'objet Toto à  cet endroit, autant maintenant il n'y a plus rien... donc il risque d'essayer d'interpréter ce qu'il y a à  cet endroit de la mémoire comme un objet alors que ça risque de plus être ça du tout.

    Il se peut que ce code fonctionne quand même et affiche l'objet Toto parce que cet emplacement mémoire pointé par t a été marqué comme étant supprimé, autorisant à  ce qu'on écrase l'emplacement mémoire à  tout moment puisqu'il n'est plus utilisé... mais si gros coup de bol on n'a pas écrasé cet objet entre temps (et ça on en a aucune garantie), il se peut que le NSLog fonctionne et ne plante pas, mais bon...


    Pour revenir sur stringByAppendingString, l'idéal est de bien différencier ses variables pour pouvoir les gérer indépendemment et pas risquer qu'une ancienne écrase une nouvelle :
    NSString* msg1 = [[NSString alloc] initWithString:@&quot;Hello world!&quot;];<br />NSString* msg2 = @&quot;et le monde lui répondit merde&quot;;<br />NSString* message = [msg1 stringByAppendingString:msg2];<br />[msg1 release]; // on a la responsabilité d&#39;appeler release sur msg1 puisqu&#39;on a fait un alloc/init dessus,<br />// c&#39;est donc à  nous de faire le release quand on ne se sert plus de msg1.
    
    On n'appelle pas release sur msg2 car on ne l'a pas créé avec alloc/initWithString, on a directement utilisé une chaà®ne constante. On n'aura pas besoin de faire de release sur message car on a utilisé un constructeur de commodité stringXXX (stringByAppendingString) qui est équivalent à  alloc+init+autorelease.

    Après il y a un sacré paquet de méthodes pour concaténer des chaà®nes : utiliser stringByAppendingString de NSString, utiliser une seule NSMutableString et lui rajouter ton msg2 à  la fin, utiliser initWithFormat:@%@%@, ... il n'y a pas une solution unique. Par contre selon la solution que tu choisis faut être cohérent et respecter les règles de gestion de mémoire indiquées dans la doc Apple (c'est à  dire si c'est toi qui crée l'objet avec alloc, copy, mutableCopy... c'est à  toi de faire le release (ou autorelease)" et de même "si tu fais un retain sur un objet, c'est aussi à  toi de faire le release (ou autorelease)", mais dans les autres cas (si tu n'as pas appelé alloc, *copy, retain) tu n'as pas à  appeler release)
  • CéroceCéroce Membre, Modérateur
    21:06 modifié #15
    dans 1237563326:

    Et vu que j'ai en général plus de facilité en commençant par la pratique et en apprenant le reste sur le tas, c'est un peu dur vu que les tutoriels bien fait pour l'objective-c sont un peu moins courant que pour les autres langages ^^


    D'où le conseil d'acheter le fameux bouquin d'Aaron Hillegass. Toutes les bases y sont justement expliquées de façon très didactiques. D'ailleurs, le livre répond à  80% des questions posées dernièrement sur ce forum.

    ça fait au moins 20 fois qu'Ali essaie d'expliquer rapidement la gestion mémoire, il n'a pas l'air de s'en lasser (?), moi si. C'est pour cela que j'ai fais exprès d'introduire des termes techniques dans ma réponse, qui sont des notions simples une fois lus les premiers chapitres du livre !
  • tet2bricktet2brick Membre
    21:06 modifié #16
    dans 1237570611:

    Encore une fois, quel rapport avec l'iPhone SDK ?  ???
    Il y a un forum " Débutants : les bases d'Objective-C & Cocoa "


    Parce que je dévelope pour l'iphone à  la base je n'ai pas l'utilité actuellement de déveloper sur mac, mais j'ai voulu aller trop vite sans doute :)

    dans 1237794631:

    D'où le conseil d'acheter le fameux bouquin d'Aaron Hillegass. Toutes les bases y sont justement expliquées de façon très didactiques. D'ailleurs, le livre répond à  80% des questions posées dernièrement sur ce forum.


    J'ai eu une entrée d'argent imprévue, le livre est commandé, je vais commencer par le commencement, merci encore pour la référence du bouquin.  ;)

    Merci à  tous pour votre aide, je reviendrais quand j'aurais quelques bases de plus
  • GreensourceGreensource Membre
    21:06 modifié #17
    En fait ce que voulais dire schlum c'est que le NSString n'est pas lié spécifiquement au développement sur iPhone, donc ton message aurais du ce trouver dans une autre partie du forum.
    Sinon amuses toi bien avec ce bouquin, moi je ne l'ai pas encore fini mais il est vraiment super! A bientôt
  • schlumschlum Membre
    21:06 modifié #18
    dans 1237814041:

    En fait ce que voulais dire schlum c'est que le NSString n'est pas lié spécifiquement au développement sur iPhone, donc ton message aurais du ce trouver dans une autre partie du forum.
    Sinon amuses toi bien avec ce bouquin, moi je ne l'ai pas encore fini mais il est vraiment super! A bientôt


    Voilà   :P

    Et puis ça m'agace les " Parce que je dévelope pour l'iphone à  la base je n'ai pas l'utilité actuellement de déveloper sur mac "
    C'est p'têt con, mais pour savoir développer sur iPhone, il faut savoir développer sur Mac, ce sont les même bases.
  • 21:06 modifié #19
    dans 1237815653:

    dans 1237814041:

    En fait ce que voulais dire schlum c'est que le NSString n'est pas lié spécifiquement au développement sur iPhone, donc ton message aurais du ce trouver dans une autre partie du forum.
    Sinon amuses toi bien avec ce bouquin, moi je ne l'ai pas encore fini mais il est vraiment super! A bientôt


    Voilà   :P

    Et puis ça m'agace les " Parce que je dévelope pour l'iphone à  la base je n'ai pas l'utilité actuellement de déveloper sur mac "
    C'est p'têt con, mais pour savoir développer sur iPhone, il faut savoir développer sur Mac, ce sont les même bases.


    <3  :-* :-* :-*
Connectez-vous ou Inscrivez-vous pour répondre.