Plist et dictionnaire

muqaddarmuqaddar Administrateur
08:41 modifié dans API AppKit #1
Salut,

Je voulais initialiser un dico à  partir d'une plist comme ça :

{
    tags = (
          toto,
          titi,
          lulu & lolo
    )
}

Bon, l'espace entre lulu et lolo fait foirer la demande, si je les vire, pas de pb, avec le bundle et le path je peux charger mon dictionnaire.
Pourquoi on ne peut pas mettre d'espace ? Comment faire pour remplir un dictionnaire (pour charger un tableau) à  partir d'un fichier dans ce cas là  ?
Merci !

Réponses

  • 08:41 modifié #2
    Dès qu'il y a une espace, tu dois mettre l'expression entre "". That's it.
  • muqaddarmuqaddar Administrateur
    08:41 modifié #3
    Merci Renaud ! 

    Tant que j'y suis, j'ai un crash mémoire :

    NSString*                       regionsPath;<br />              NSDictionary*           regionsValues;<br />            regionsPath = [[NSBundle mainBundle] pathForResource:@&quot;Regions&quot; ofType:@&quot;plist&quot;];<br />             regionsValues = [NSDictionary dictionaryWithContentsOfFile: regionsPath];<br />         tabRegions = [[NSMutableArray alloc] init];<br />               tabRegions = [regionsValues objectForKey: @&quot;regions&quot;];
    


    Apparemment, ça vient de la dernière ligne.
    tabRegions est une varoable d'instance. Je m'en sers dans d'autres méthodes.
  • BruBru Membre
    08:41 modifié #4
    dans 1099901095:

    Tant que j'y suis, j'ai un crash mémoire :

    NSString*                       regionsPath;<br />              NSDictionary*           regionsValues;<br />            regionsPath = [[NSBundle mainBundle] pathForResource:@&quot;Regions&quot; ofType:@&quot;plist&quot;];<br />             regionsValues = [NSDictionary dictionaryWithContentsOfFile: regionsPath];<br />         tabRegions = [[NSMutableArray alloc] init];<br />               tabRegions = [regionsValues objectForKey: @&quot;regions&quot;];
    


    Apparemment, ça vient de la dernière ligne.
    tabRegions est une varoable d'instance. Je m'en sers dans d'autres méthodes.


    3 choses :

    - dans les 2 premières lignes du code, il faut tester les valeurs de retour (regionsValues et regionsValues). Si pour une raison ou une autre, l'appel aux méthodes échoue, ça renvoie nil. Comme tu ne testes pas ces cas, tu risques de te trimbaler des nils un peu partout jusqu'à  ce que ça te fasse planter à  un moment donné ton appli.

    - Avant dernière ligne : tu créés un tableau (NSMutableArray) et tu places sa référence dans la variable tabRegions. Mais 1 ligne plus bas, tu écrases cette référence par une autre référence de tableau provenant de objectForKey:. Résultat, peu à  peu, tu remplis la mémoire de ton appli par des NSMutableArray jamais détruits (on appele ça un mémory leak).

    - dernière ligne : le tableau retourné par objectForKey: est en autorelease, c'est à  dire que son allocation est temporaire, et qu'il sera détruit à  la prochaine boucle d'événement. Si tu veux le garder "longtemps", tu dois faire un retain dessus.

    .
  • muqaddarmuqaddar Administrateur
    08:41 modifié #5
    Merci Bru.
    J'ai compris et réparé les 2 derniers points. ça marche.
    En revanche, je ne comprends pas ce que je dois faire / ajouter pour le premier point. Qu'appelles-tu tester les valeurs de retour de regsionsValues et regionsPath ?
  • BruBru Membre
    novembre 2004 modifié #6
    dans 1099902406:

    En revanche, je ne comprends pas ce que je dois faire / ajouter pour le premier point. Qu'appelles-tu tester les valeurs de retour de regsionsValues et regionsPath ?


    Un truc du style :
    [tt]
    {
        NSString *regionsPath;
        NSDictionary *regionsValues;

        regionsPath = [[NSBundle mainBundle] pathForResource:@Regions ofType:@plist];
        if ( !regionsPath ) NSLog(@erreur sur l'accès à  la ressource de Regions.plist\n);
        else
        {
            regionsValues = [NSDictionary dictionaryWithContentsOfFile: regionsPath];
            if ( !regionsValues ) NSLog(@erreur sur lecture du contenu de Regions.plist\n);
            else tabRegions = [[regionsValues objectForKey: @regions] retain];
        }
    }
    [/tt]

    .
  • muqaddarmuqaddar Administrateur
    08:41 modifié #7
    Ah oui, OK. Logique.
    Néanmoins, faudrait vraiment que le gars soit allé virer le fichier à  l'intérieur du paquet de l'application...
    Mais enfin, oui, il vaut mieux éviter.

    D'ailleurs, vous avez un moteur d'affichage des erreurs dans vos applications je suppose ?
    Genre, on envoie un paramètre à  une fonction qui crée l'alerte avec le paramètre...
  • BruBru Membre
    08:41 modifié #8
    dans 1099904514:

    Ah oui, OK. Logique.
    Néanmoins, faudrait vraiment que le gars soit allé virer le fichier à  l'intérieur du paquet de l'application...


    Dans mon boulot, j'ai vu des utilisateurs (de mes applis) faire pire...

    Donc, il faut tout prévoir.

    .
  • muqaddarmuqaddar Administrateur
    08:41 modifié #9
    OK.

    Néanmoins, je voulais faire un test comme ça :

    //chargement des regions avec le fichier texte<br />            NSString*                       regionsPath;<br />              NSDictionary*           regionsValues;<br />            regionsPath = [[NSBundle mainBundle] pathForResource:@&quot;Regions&quot; ofType:@&quot;plist&quot;];<br />             if (!regionsPath) {<br />                       [self alerteUser:@&quot;Aucun fichier plist n&#39;a été trouvé pour les régions ! Résinstallez l&#39;application !&quot;];<br />              }<br />         else {<br />                    regionsValues = [NSDictionary dictionaryWithContentsOfFile: regionsPath];<br />                 tabRegions = [[regionsValues objectForKey: @&quot;regions&quot;] retain];<br />}<br />
    


    et

    - (void)alerteUser:(NSString*)message<br />{<br />        NSBeep();<br /> NSBeginAlertSheet(@&quot;Warning !&quot;, @&quot;OK&quot;, nil, nil, mainWindow, self, @selector(sheetDidEnd:returnCode:contextInfo:), nil, nil, message);<br />}
    


    Sauf que si je vire le fichier plist du bundle, il refuse tout bonnement de me lancer l'appli et donc je ne peux tester l'alerte !
  • BruBru Membre
    08:41 modifié #10
    dans 1099905230:

    Sauf que si je vire le fichier plist du bundle, il refuse tout bonnement de me lancer l'appli et donc je ne peux tester l'alerte !


    As tu quelque chose dans la log ?

    .
  • muqaddarmuqaddar Administrateur
    novembre 2004 modifié #11
    Oui, oui, il me réclame le fichier dans une erreur.
    "No such file or directory"
  • 08:41 modifié #12
    ça c'est quand tu le vires depuis Xcode il me semble. Il aller le virer par le Finder, puis aller dans le bundle et de là  le virer.
  • BruBru Membre
    08:41 modifié #13
    dans 1099906421:

    ça c'est quand tu le vires depuis Xcode il me semble. Il aller le virer par le Finder, puis aller dans le bundle et de là  le virer.


    Je crois que c'est l'inverse...

    Dans Xcode, il y a toujours la référence au fichier regions.plist (dans le groupe Resources), mais t'as dû le viré depuis le Finder...

    .
  • muqaddarmuqaddar Administrateur
    novembre 2004 modifié #14
    Oui exactement Bru.

    Si quelqu'un a une idée concernant le fait que ma sheet devienne une alerte classique au démarrage de l'appli ... ? Est-ce parce qu'elle est chargée ds le init avant le nib ?
  • 08:41 modifié #15
    OK toutes mes excuses, je voulais dire dans le dossier contenant les sources. Mais je maintiens que pour le virer proprement, il faut aller dans le bundle du projet compilé ;) J'ai été un peu vite...
  • BruBru Membre
    08:41 modifié #16
    dans 1099906797:

    Si quelqu'un a une idée concernant le fait que ma sheet devienne une alerte classique au démarrage de l'appli ... ? Est-ce parce qu'elle est chargée ds le init avant le nib ?


    Je pense que oui !

    Je suppose que t'as mis tout ça dans un awakeFromNib...
    Dans ce cas, la fenêtre à  laquelle tu tentes d'attacher ton alerte n'est pas encore à  l'écran (même si elle est déjà  en mémoire), donc l'alerte devient classique.

    .
  • muqaddarmuqaddar Administrateur
    08:41 modifié #17
    Non, tout ça est dans le init() justement, qui se charge avant le awakeFromNib, comme me l'a confirmé Renaud... Mais effectivement, la fenêtre d'alerte est bien affichée avant la fenetre auquelle elle est attaché : mainWindow.
  • muqaddarmuqaddar Administrateur
    novembre 2004 modifié #18
    Autre chose : je viens de remarquer que les données issus du plist perdaient leur accent à  l'affichage de mon tableView.
    Est-ce une histoire d'encodage ?

    Le message d'erreur :

    CFPropertyListCreateFromXMLData(): plist parse failed; the data is not proper UTF-8. The file name for this data could be:
    /Users/oxitan/Cocoa/Prod/MyApp/build/MyApp.app/Contents/Resources/Regions.plist
    The parser will retry as in 10.2, but the problem should be corrected in the plist.
Connectez-vous ou Inscrivez-vous pour répondre.