NSTreeController et fichier plist. Une équivalence simple?
Bonjour,
Je cherche ni plus ni moins à reproduire dans une application l'équivalent simplifié de l'éditeur de fichier plist d'Xcode (sélection sans édition).
J'ai donc dans mon bundle un fichier plist avec une arborescence. J'aimerais retrouver cette structure dans une NSOutlineView commandée par un NSTreeController.
J'ai vu quelques exemples sur le web, y compris les deux exemples d'Apple. Mais comme tout cela a l'air tellement simple sur le fond, les auteurs en rajoutent des masses: ils recréent des nodes à partir de NSObject, implémentent des datasources, flanquent tout ça dans des view-based tableViews pour rajouter des images, démontrent leur maà®trise du reordering par drag and drop...
Résultat : le code élémentaire que je recherche est noyé dans des options merveilleuses... dont je n'ai cure.
Je suis parvenu à faire tourner quelque chose, mais l'app utilise deux classes... et ne permet qu'un niveau de hiérarchie!
Mes buts:
1. Lecture du dictionnaire et parsing
2. Utilisation d'une classe unique dérivée de NSTreeNode (isLeaf or not)
3. NSOutlineView de base dans IB
4. NSTreeController avec bindings.
Auriez-vous un exemple à me proposer qui réponde à ces caractéristiques?
Merci d'avance!
J'ai trouvé ça, qui se rapproche beaucoup de ce que je veux:
mais je n'arrive pas à le faire fonctionner. Il me retourne
plist
dict
key
Chapitre 1
array
string
Paragraphe 1 (leaf)
...
au lieu de
Chapitre 1
Paragraphe 1 (leaf)
Réponses
Bon, ni ce forum ni les autres ne semblant avoir de solution, et après avoir erré durant des heures, je me suis décidé pour une solution peut-être atypique, peu conforme et finalement assez lâche. Mais un lâche vivant valant mieux qu'un héros mort (de fatigue en tout cas) voici comment j'ai fait.
J'ai construit un "éditeur d'arborescence" dans une autre application. Elle possède un xib minimal: une fenêtre comportant une NSOutlineView, un NSTreeController, trois boutons reliés aux méthodes add:, addChild: et remove: du contrôleur. A l'aide de ces boutons, je compose mon arborescence, intitulés des nodes compris.
J'ai deux autres boutons: "Dump" qui effectue cette méthode dans mon appDelegate:
et "Load" qui effectue ceci:
Ainsi, je sauve dans un fichier binaire mon arborescence. Il me reste à glisser ce fichier dans le bundle de mon autre application. Au lancement de celle-ci, j'effectue la même opération que le "load" de mon éditeur.
Les avantages sont les suivants:
- une seule ligne de code
- aucune dérivation (ni nodes, ni child, ni leaf, etc)
- l'ordre est le même que dans l'éditeur (allez donc fabriquer des SortDescriptors pour une arborescence!)
- l'arborescence peut à tout moment être reprise et modifiée dans l'éditeur.
OK, Ulysse n'était pas Achille, mais il était malin... et il s'est sorti vivant de Troie.
J'arrive un peu tard mais tu aurais pu essayer de reprendre les données du .plist sous forme de dictionnaire et en faire une analyse générique pour ta datasource : Array / Dictionary -> node, string / date / number -> leaf. Ou même, plus simple et très peu de code pour toi : tu reprends in extenso l'exemple d' Apple mais en désarchivant d'abord ton plist dans un dictionary puis en le réarchivant au format XML que tu aurais alors donné en pature à ton "treeController" , je ne sais pas si ça aurait marché car l'exemple est à base d'un XMLDocument or je ne sais pas si un fichier plist archivé XML est un NSXMLDocument pour autant.
Bonjour laudema,
Merci pour la réponse -- même tardive elle est bienvenue: mon "astuce" ne fonctionnerait pas pour une OutlineView dynamique, par exemple. Là ça marche parce qu'elle est statique (c'est une sorte de menu avec des sous-menus, sous-sous-menus etc).
Les avis sur le net sont partagés (je ne sais pas si c'est lié à la maà®trise de l'auteur du message) mais il y a ceux qui disent "C'est tout simple, regardez" et qui mettent en zip un projet avec six classes dérivées et des centaines de lignes de code, et ceux qui confessent "NSOutlineView est l'une des classes les plus difficiles à comprendre et mettre en oeuvre"...
Mon opinion est la même que pour Core Data. Pour une utilisation minimale, "sortie du carton", c'est magique et ça fait tout tout seul, quelques bindings, zéro code et youpie. Là tu penses : c'est génial, je vais me concentrer sur le reste du code...
Et puis tu veux adapter un petit truc, comme installer des entités par défaut dans un document, ou copier des entités d'un document à l'autre, ou une OutlineView qui affiche dans un gradient les nodes qui ont des childnodes... et... ça devient moins magique!
D'un côté c'est bien, ça évite, côté vue, les comportements folkloriques des classes standard et l'utilisateur s'y retrouve. Mais côté contrôleur et modèle, tu galères...
De toute façon je reviendrai sur le sujet, parce que j'ai juste évité de me prendre la tête sur ce coup-ci, mais je ne pourrai pas toujours.
Quant aux plist et xml, il m'a semblé qu'ils étaient une seule et même chose, mais cela demande confirmation...
Pas tout à fait. Un Plist peut être représenté sous forme de fichier XML.
Il suffit de voir les premières lignes d'un fichier plist.
Il existe aussi une forme binaire pour un Plist, dans ce cas ce n'est pas un XML.
Merci pour la précision, jpimbert.
Donc les plist sont un sous-ensemble de XML. Voilà pourquoi ma plist était acceptée par NSXMLDocument. Mais je me retrouvais tout de même avec une OutlineView remplie par des balises (que j'aurais voulu éliminer). Après avoir étudié l'exemple d'Apple de plus près, ce sont bel et bien des balises qui sont listées dans la OutlineView. Mais comme elles sont différentes des "array", "key" et autres "dict", j'ai cru qu'il s'agissait de valeurs et pas de clés...
Perso, je serais passé par un datasource : dans un premier temps, comme dit par Laudema, tu transformes ton plist en dico ou en array ; ensuite tu implémentes le datasource.
Sinon, il y a aussi ces tutos : Cocoa Programming L49 - NSOutlineView Intro - YouTube
et Cocoa Programming L50 - NSOutlineView editing - YouTube
De ce que j'ai lu quand j'avais essayé de m'en servir, elle a surtout (aussi) la réputation d'être la plus bugguée, à cause de son origine de NSTableView.
A l'époque ça me paraissait on ne peut plus plausible et le meilleur moyen que j'ai trouvé pour arriver à mes fins c'était de laisser tomber NSTreeController pour utiliser un datasource. Dès qu'on veut personnaliser un peu et avoir du contrôle sur l'affichage ça semble plus sage.
Certainement... et tellement moins glamour ???. Mais c'est vrai que ça a le mérite d'être explicite. Aller chercher un bug dans les bindings peut tourner au cauchemar tant c'est éparpillé...
Non pas tout à fait : Les fichiers PLIST représentent une arborescence de données pouvant contenir qu'un certain type de données restreint (string, data, array, dico...). La façon dont ils sont stockés sur disque varie ensuite :
- ils peuvent être stockés sous forme ASCII (format de plus en plus déprécié, on ne peut même plus sauver à ce format avec les dernières API, mais il est encore supporté (c'est le format utilisé par les fichier ".strings" d'ailleurs qui ne sont rien d'autre en vrai que qu'un PLIST contenant un dictionnaire de string)
- ils peuvent être stockés sous format XML (format assez courant pour le stockage d'un PLIST, et facile à parser avec un parseur XML et à éditer avec un éditeur de texte, donc format assez pratique)
- ils peuvent aussi être stockés au format Binaire (Binary PLIST), qui est un format incompréhensible à l'oeil humain mais a l'avantage d'être très compact (format utilisé quand tu compiles une appli iOS par exemple où tous les PLIST et .strings sont convertis dans ce format pour prendre moins de place sur le disque)
Bref c'est un peu comme une image : elle peut être sauvée en PNG, en JPG, en TIFF, en BMP... au final c'est la même image et les même données dedans mais il existe plusieurs formats pour stocker ces mêmes données. Un PLIST qui est au format XML tu pourras le parser avec un NSXMLDocument, mais s'il est au format binaire ou ASCII ça ne marchera évidemment pas