Plantage dû peut-être à un unichar*
Greensource
Membre
Bonsoir! Je me fait une mini appli qui gèrent des chaines de caractères.
Je dois récupérer le milieu d'une NSString, c'est à dire sans son premier et dernier caractères. Voilà comment je mis suis pris:
Le souci c'est que mon appli plante mais pas dans cette fonction. Ca coince quand elle sort d'une IBAction:
C'est quand je sort de cette fonction que j'ai un:“EXC_BAD_ACCESSâ€
J'ai penser que ça pouvais venir du unichar*, je ne sais pas trop comment l'initialiser...
Je dois récupérer le milieu d'une NSString, c'est à dire sans son premier et dernier caractères. Voilà comment je mis suis pris:
<br />- (NSString*)wordWithoutBounds:(NSString*)theWord<br />{<br /> unichar* buffer;<br /> [theWord getCharacters:buffer range:NSMakeRange(1, [theWord length]-1)];<br /> return [NSString stringWithCharacters:buffer length:[theWord length]-2];<br />}
Le souci c'est que mon appli plante mais pas dans cette fonction. Ca coince quand elle sort d'une IBAction:
<br />- (IBAction)shake:(id)sender<br />{<br /> NSString* inputString = [[input stringValue] retain];<br /> NSString* middleWord = [self wordWithoutBounds:inputString];<br /> NSLog(@"%@",middleWord);<br />}
C'est quand je sort de cette fonction que j'ai un:“EXC_BAD_ACCESSâ€
J'ai penser que ça pouvais venir du unichar*, je ne sais pas trop comment l'initialiser...
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Donc j'ai fait ça:
Mais je veux bien quand même des retours sur ma façon de faire ma fonction, j'ai l'impression qu'il y a plus simple.
Et aussi, dois-je vérifier que l'allocation c'est bien faite? Sachant que de toutes façons je ne renvoie pas d'erreur.
Merci
Là par exemple "getCharacters: range:" est sensée prendre en premier paramètre un buffer... déjà alloué ! Comme dit dans la doc : Donc là tu as oublié d'allouer la mémoire (avec malloc, la bonne vieille fonction C qu'on aime oublier quand on fait du Cocoa) dans ton buffer... ([EDIT]Bon ben depuis tu as vu, mais ça suffit pas...[/EDIT]) ... et ne pas oublier de la libérer (free)... après avoir construit ta NSString avec, et avant ton return...!!
Du coup en fait quand tu essayais d'afficher la NSString générée (via ton NSLog), il va lire dans ce buffer initialisé n'importe comment et lire n'importe où dans la mémoire car tu n'as pas initialisé ton "unichar* buffer". D'où le EXC_BAD_ACCESS logique.
Quand même contraignant, ces méthodes getMachin utilisant les types C et surtout les unichar*, hein ?
Mais dis moi, pourquoi ne pas utiliser substringWithRange: ??
Mais bon, je dis ça mais je sais pas...
Par contre, en C allouer une chaà®ne de caractères avec un seul caractère et y mettre bien plus long ça risque de faire de la casse... :brule:
Mais heuuu, je l'avais pas vu :P
Je suis deg' je suis passer à coté comment neuneu. Ca fait 1/4 que je me dit qu'ils abusent et qu'ils auraient quand même pu la faire cette méthode ^^
Merci bien les gars
Merci! Je m'en fait une spécialité
A mes débuts, j'avais pris l'habitude de l'utiliser, et je trouvais ça bien...
Mais j'ai vite réalisé que du coup à cause de sa possibilité de lister les méthodes de la classe mais aussi de ses superclasses toutes en même temps... je n'intégrais pas au fur et à mesure de mes fouilles dans cette doc AppKiDo à quelle classe appartenait réellement telle ou telle méthode.
Du coup quand on cherche une méthode particulière, oui c'est pratique car il liste toutes les méthodes qu'une classe supporte, en prenant en compte les classes parentes. Mais ça ne forme pas à Cocoa forcément super, du coup.
Pour moi, c'est à utiliser occasionnellement, quand on cherche une méthode spécifique par exemple, mais pas pour autant systématiquement. Rien ne vaut apprendre à lire dans la doc Apple (qui s'avère plutôt bien foutue en général) comme ça quand on a un problème, on a pris l'habitude de chercher au bon endroit. Et au fur et à mesure, l'organisation des classes Cocoa commence à rentrer.
Donc je ne dénigre pas AppKiDo, mais disons que c'est un peu comme les bindings ou quoi : ça simplifie les choses, ça semble une bonne idée pour les débutants... mais ça a un effet pervers a long terme, donc il est préférable de prendre les bonnes vieilles méthodes à terme
J'arrive pas à comprendre pourquoi ce plantage surviens plus tard? C'est impossible à tracé du coup!
Pour l'instant je dirais que ça viens de là :
Quand je vire l'appel de cette fonction ça passe donc ça dois venir d'ici. Au début je faisait des release sur chaque objet mais après je me suis dit qu'il devais être en autorelease donc pas touche. Mais ça plante toujours.
Et que donc si personne ne fait de "retain" dessus, il sera détruit au prochain cycle de runloop...
Non en effet je n'avais pas penser à ça. J'ai modifié l'appel à cette méthode du coup:
Mais j'ai toujours ce plantage. J'ai passer Clang dessus pourtant et ça semble bon.
[edit] Bon c'est en effet plein d'erreur de retain et release, j'avais un packet d'erreur de libération de mémoire. J'ai changer tout ça mais pour moi j'ai une fuite de mémoire ici:
Or Clang ne me dit rien, bizarre non?
Ta gestion de la mémoire a l'air d'être un beau bazar !
si "result" est une i-var, pourquoi ne pas utiliser le setter au lieu d'appeler des release / retain directement dessus...
Bon là je vais aller au dodo, je vous file là où j'en suis rendu.
Pour la petite explication, ce soft prend un texte en entré, il fait ensuite un mélange à l'intérieur de chaque mot. Il garde uniquement la position de la première et dernière lettre de chaque mot. Finalement on se rend compte qu'un texte traiter de cette façon est encore à peut près lisible.
[une partie du message passé dans WordShaker:]
Bon il reste plein de réglage à faire, ça plante si on met un trop grand texte etc...
Tu devrais plutôt filer les sources qu'on te dise ce qui n'est pas bien...
Ahum...oui bon c'est sûr je suis pas le plus doué pour ça :P
Voici les sources
Exact! Et aussi parce qu'il était 2h du mat' et que je voulais quelques chose qui tourne avant de dormir ;-)
En tous cas ça va me faire un autre projet où apprendre la gestion de la mémoire!
Si je me rappelle bien et si j'ai bien compris, dès que dans la doc c'est écrit quelque chose du genre:
Et il faut comprendre qu'il y a un autorelease dessus c'est bien ça?
Nième rappel concernant la gestion mémoire des objets :
règle 1 : tu créés un objet (par alloc/init, new ou copy) -> c'est à toi de le détruire (par un release).
règle 2 : on te donne un objet tout fait (par exemple en résultat d'appel d'une méthode) -> comme tu ne l'as pas créé, alors tu ne dois pas faire de release.
règle 3 : tu obtiens un objet (par exemple en résultat d'une méthode) que tu n'as pas créé, mais tu veux être certain de le garder longtemps, alors tu fais un retain dessus. Une fois que tu es sûr de ne plus avoir besoin de cet objet, alors tu lui appliques un release.
Entre le point 2 et 3 par exemple. Tu dis que l'ont à pas à faire de release, donc cela suppose qu'il y a un autorelease de fait dessus n'est-ce pas? Du coup si par exemple je met cet objet retourné dans un tableau, dois-je faire un retain pour pas qu'il disparaisse? Ou plutôt dans mon cas précis, si je le donne à afficher à un NSTextField, dois aussi faire un retain?
La question reviens à : Lors de l'ajout d'un objet via une méthode, un retain est-il fait dans cette méthode. Ici :[anArray addObject:anObject atIndex:anIndex] y aura t'il un retain de fait?
Je vais essayer de faire du nettoyage pour amélioré tout ça. Merci
Dès que tu le sors de cet objet, ça va faire un release dessus.
Si l'objet que tu mets dans ce tableau a été créé par toi, et si après la mise en tableau tu en a plus besoin, tu release (mais il ne disparaitra pas grâce au retain interne du tableau).
J'ai pris l'exemple du tableau, mais cela vaut pour toutes les collections (dictionnaire, set, etc) d'objets.
* Déjà pour avoir du hasard de qualité, il faut utiliser "/dev/urandom", puis tu lis dedans d'un coup (nombre de lettres-1)*sizeof(NSUInteger)
* Ensuite, tu inverses chaque lettre (sauf la dernière) avec une des suivantes ou elle même (et pas avec une au pif)
Pour faire ça, pour le coup, vaut mieux récupérer le tableau de caractères !
Pour le random, je ne sais pas comment importer ton truc, faut faire #import "dev/urandom"?
Pour ce qui est du mélange je pensais déjà faire ce que tu dis, j'ai pas fait ça?
Cette fonction fait tout... Elle mélange le milieu du mot quand il fait plus de 3 lettres.
J'ai une ou deux questions qui demeure:
Tu ouvres le fichier urandom, il y a quoi dedans? Des nombres aléatoires? Et tu lis les x premiers dont tu as besoin c'est ça? C'est pas sensé être un programme urandom?
Ce genre d'astuce que j'utilise 2 fois et qui n'est pas forcément claire au premier regard, c'est pour éviter un "malloc", et allouer un buffer de la taille que je veux sans me préoccuper de leaks ou d'exceptions. Un buffer C auto-released en gros.
C'est bien ça?
Bon sinon je crois avoir chassé les problèmes de mémoire, je vous reposte le projet. Je vais aussi faire une annonce là ou ça va bien, je suis un peu hors sujet ici.
"lg*sizeof(unichar)", pas juste "sizeof(unichar)"... je veux allouer pour tout le mot, pas pour juste un caractère !
ça remplace ça, mais c'est plus intelligent car le free est géré par l'AutoRelease pool, et sera donc fait dans tous les cas.