Stocker une chaà®ne obtenue par référence dans un NSMutableDictionary
laudema
Membre
Bonjour,
Une méthode a pour objet de parcourir un fichier texte d'une série de lignes au format "clef=valeur" et d'en extraire un dictionnaire
Mais ça marche pô, mon mutable dictionary reste vide.
Par contre si je remplace setObject par setValue
Serait il plus sage de mettre setObject:[NSString stringWithString:value] ?
Une méthode a pour objet de parcourir un fichier texte d'une série de lignes au format "clef=valeur" et d'en extraire un dictionnaire
<br />NSString *key, *value;<br />while (! [subScan isAtEnd]) { <br /> [subScan scanUpToString:@"=" intoString:&key];<br /> [subScan scanString:@"=" intoString:NULL];<br /> [subScan scanUpToString:@"\r\n" intoString:&value];<br /> [subDic setObject:value forKey:key]; <br />}
Mais ça marche pô, mon mutable dictionary reste vide.
Par contre si je remplace setObject par setValue
[subDic setValue:value forKey:key];
Là ça fonctionne mais j'ai des doutes sur la pérénnité de value en sachant que le dictionnaire la contenant sera mis dans un tableau avant d'être relâché puis le tableau renvoyé "autoreleased" à une autre classe.Serait il plus sage de mettre setObject:[NSString stringWithString:value] ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Il se passe quoi dans tes méthodes:
scanUpToString:intoString: et scanString:intoString: ?
La méthode utilise un scanner de la classe NSScanner. à un objet scanner on passe des variables par référence: on déclare une NSString, un int ou un float etc et on passe l'adresse de la variable à la méthode http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/Strings/Articles/Scanners.html#//apple_ref/doc/uid/20000147-BCIEFGHC , c'est ce que j'appelais "chaà®ne obtenue par référence"
Si je fais un log de mes chaines elles sont bien là dans le terminal. À chaque itération l'adresse change et le type est un NSCFString.
Donc pas forcément un objet au sens Objective-C et pourtant une chaà®ne.
J'aurais dû y penser avant puisque http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/uid/20000154-10850
Alors on peut faire un cast ...
Ici, caster la chaà®ne ne change absolument rien pour le code généré. L'objet ne change pas, les retain/release seront rigoureusement les mêmes. Il n'est pas normal à la base que setObject:forKey: et setValue:forKey: se comportent différemment dans ton morceau de code, il doit y avoir un problème ailleurs.
Si la mémoire n'est pas critique, au lien des NSScanner, et que tu es sûr que tes chaà®nes ne contiennent pas le caractère "=", tu peux te simplifier la vie avec "componentsSeparatedByCharactersInSet:" et "componentsSeparatedByString:". Si tu veux faire ça rigoureux, ben... regex ! (c'est à la mode on dirait )
Mais faudrait logger un peu ce qui se passe, parce qu'à moins que la chaà®ne contenue dans "key" commence par un "@", setValue:forKey: et setObject:forKey: devraient faire la même chose ici.
T'es sûr qu'une exception est pas levée dans certains cas pour un key ou une value qui se retrouverait égal à nil ?
J'ai regardé les regex mais ça n'existe pas dans Cocoa il faut utiliser une librairie externe ou passer par un script.
Par contre il me semble (relativement) logique que setObject:ForKey: ne fonctionne pas car ce qui est retourné à travers &value n'est pas un objet mais un "typedef const struct __CFString * CFStringRef" donc l'appel est ignoré car ce n'est pas nil non plus !
Aucune exception, aucune modification, je pourrais commenter la ligne j'aurais le même résultat !
setValue:ForKey utilise setObject:ForKey après avoir vérifié que value!=nil, c'est peut être là que value qui est une structure devient un objet Cocoa.
Apple donne t'il le source de ces méthodes ? J'aurais aimé y jeter un oeil
Ouaip. NSPredicate est un peu limité, mais regexkitlite est un super framework (à regarder à l'occasion, là on déborde du sujet qui nous préoccupe).
Caster ne fait que réinterpréter le pointeur pour que le compilateur ne râle pas, mais ici ça ne va rien changer du tout. De toutes façons, c'est encore casté en (id) pour être passé en paramètre à setObject/Value:forKey:
Une NSString* est une CFStringRef, et inversement ; ce sont des pointeurs, il n'y a pas de conversion interne ; comme tu l'as dis, ça fait partie des classes "toll free bridge" entre Cocoa et CoreFoundation.
Un truc tout bête : est-ce que si tu isoles complètement ton code (du genre qu'on puisse le reproduire sur nos machines), ça donne le même problème ?
J'ai fait un essai avec un fichier .strings:
et ça donne pour le dico:
Si c'est encore casté id alors je ne devrais pas avoir besoin de caster NSString ?
Tu as vu ça où ?
`
C'est déjà du code isolé, je teste ça dans une application "Foundation Tool" et si ça marche je le ré-incorpore dans mon appli.
Voici le code copié tel quel, une partie sert à enlever les commentaires( lignes commençant par un , là le but était de me familiariser avec NSRange dans une chaà®ne. C'est sûr que, pour ça, travailler sur un tableau c'est plus facile 8--)
Et éventuellement un lien pour "FichierTest.txt" http://voui.free.fr/Telechargements/FichierTest.txt
Je suis très mécontent de ne pas savoir l'ouvrir avec la ligne de code de mpergand d'ailleurs, c'est ce que j'avais tenté en premier mais sans succès
Chez moi
ça ne fonctionne pas non plus d'où cet horrible bricolage au début
NSMutableDictionary *leDico = [NSMutableDictionary dictionaryWithCapacity:10] ;
[leDico setDictionary:[NSDictionary initWithContentsOfFile:cheminDuFichier]] ;
Bien sur, il faut être sur de la syntaxe du fichier traité.
Normal, un fondationTool n'est pas un bundle ...
Bon, mon code marche avec ton fichier, mais le problème c'est qu'il y a plusieurs entrées avec le même nom (date ...)
Il faut donc faire un parse par section.
Pourtant ce matin je testais encore en enlevant le cast sur key il retenait, en enlevant sur value il retenait plus. Maintenant il retient tout..
Bah oui, je l'avais oublié, d'où son entêtement à se voir dans le répertoire /build/Debugg/ il se situe au niveau de l'exécutable... logique as usual
Mais bon, sans tâtonner je n'aurais pas cherché à "clean all targets" et je ne saurais pas que finalement mon code est valide et que je vous ai dérangé pour rien.
Mille excuses
Finalement je pense garder quand même les explode, c'est vrai que ça va vite et puis c'est plus facile pour traiter les commentaires et autres lignes sans "=". Et la prochaine fois je n'hésiterais pas non plus à me servir de NSScanner si besoin ...
Merci à tous
setObject/Value:(id)value forKey:(id)key prennent des id. Donc les paramètres sont castés en (id) à l'appel de la fonction. Mais ça ne change rien, c'est juste une interprétation de l'adresse contenue dans le pointeur pour faire plaisir au compilateur (et lever des warnings si c'est louche).
Donc, non, caster en NSString* ne sert à rien ici.
Maintenant que tu le dis ça me saute aux yeux
Jusque là je pensais qu'il n'y avait qu'une vérification de faite, je n'imaginais pas que c'était de cette manière.
Ca se fait en une seule ligne et basta.
Or ce n'est pas moi qui crée le fichier mais une appli tierce, venant du monde PC, et qui ne semble pas savoir ce qu'est une "valid representation of a dictionary", en tout cas pour Cocoa.
Corriger le fichier pour qu'il soit lisible par dictionaryWithContentOfFile serait encore plus compliqué
PS: Où trouver la documentation sur la petite icône à droite de chaque titre des messages du forum (plaque de chocolat) ? La tasse pleine ou vide est "self-documented" mais je me demande ce que représente la petite plaque de chocolat 8--)