[Swift]Accès aléatoire à un fichier de NSDictionnary
Voici mon problème. J'aimerais stocker un tableau de NSDictionnary dans un fichier, pour y accéder ensuite en chargeant qu'un seul élément, sans relire tous les autres.
Un exemple (fictif), imaginons que je veuille réaliser un catalogue d'herbes chinoises, avec un nom, une image et une description. Et la consulter dans une UIViewCollection. Si ma base contient 500 herbes, je n'ai pas envie de TOUT charger en mémoire pour accéder à une seule fiche.
Avez-vous une suggestion pour réaliser ça simplement, sans déployer l'artillerie lourde ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
L'artillerie lourde c'est CoreData ?
Sinon je ferais un fichier binaire composé d'un entête contenant une liste fixe d'offset (genre 500 ou plus). Chaque offset donnant accès un enregistrement dont les données serait codée aux format TLV. Les ajouts et les suppression sont assez facile et il faut juste faire une petite restructuration du fichier de temps en temps pour récupérer la place perdu lors des suppressions.
Oui, l'artillerie lourde c'est Core Data dont j'ignore tout. J'avais pensé à un fichier binaire, mais cela me rappelle un peu trop l'informatique de mes jeunes années. J'espérais une solution plus simple et plus moderne.
Je n'ai pas besoin de restructuration. L'idée c'est de générer le fichier à partir d'une moulinette sur Mac, pour l'exploiter dans une application iOS.
Si le nombre d'objets est bien dans les 500, et à moins que tu vises l'iPhone 3G, tu peux tout charger en mémoire (sauf les images).
A ta place, je stockerais les données dans un plist binaire en utilisant NSKeyedArchiver et NSCoding, car tu n'auras presque rien à faire.
Pour les images, tu les stockes à côté en ne mettant que le nom du fichier image dans les données.
Le mieux c'est de faire un test de perf. Cela te prendra une heure.
En même temps, si tu as du temps, c'est un bon moyen d'apprendre CoreData ou Sqlite.
Merci, je vais essayer.
J'ai besoin de développer une application, pas d'apprendre une nouvelle technologie, sauf si c'est absolument indispensable.
Pour ce cas de figure se mettre à CoreData ne serait pas une si mauvaise idée.
C'est une techno qui fait peur pour ce qu'on en a lu sur le net mais dans un cas simple comme le tiens ça serait vraiment dommage de se priver de: 1. la faciliteÌ (si, si), 2. les performances.
En plus le modeÌ€le a l'air très simple l'inteÌgration va même être faciliteÌe. Je suis prêt à t'aider meÌ‚me.
CoreData c'est comme le cafeÌ: au deÌbut on y touche pas parce que ça a l'air deÌgueulasse mais une fois qu'on a le nez dedans on fait avec son coÌ‚teÌ amer et on commence meÌ‚me à l'apprécier.
On peut aussi mettre beaucoup de sucre !
Tais-toi malheureux, j'ai encore des kg à perdre ..
Pourquoi pas. Je résume les choses. J'ai un tableau d'objets FicheHerbe composé de :
- un nom (une string)
- une description (une autre string)
- une image (une UIImage)
Je voudrais enregistrer tout ça dans un fichier et pouvoir accéder librement à n'importe quelle fiche.
Mais il n'y a pas qu'un seul fichier (ce serait trop simple). Je veux pouvoir créer d'autres bases de données, pour les mettre en téléchargement sur internet (dans un in-app ou sur un site). Par exemple, l'application serait fournie avec "Les herbes chinoises", l'utilisateur pouvant par la suite télécharger "Les herbes d'Afrique", "Les herbes d'Asie", "Les herbes de nos jardins français", etc ..
Après il y a aussi la possibilité de faire une serialization custom en pure swift.
Quelque chose inspiré de NSCoding mais en plus simple, adapté à ton cas.
Cela te permettra de ne pas dépendre d'un framework si tu veux réutiliser un jour tes données sur un serveur web ou une app Android.
Je pense qu'à l'heure où swift devient multi-plateforme, il faut s'écarter de certaines solutions trop orienté Apple pour les couches qui ne sont pas strictement du GUI, comme les couches de modèle ou de serialization.
ça se complique...
Android .. euh .. je n'y mettrais JAMAIS les pieds ! Cela ne veut pas dire que je ne payerais pas quelqu'un pour le faire à ma place, le laissant s'occuper des détails techniques.
Il faudrait que tu aies dans Core data une base de données comme ceci :
Lot : IDLot, NomLot
FicheHerbe : IDFiche, nomFiche, descriptionFiche, imageFiche, IDLot
tu accèderas au fichier voulu par l'index IDLot non?
Comme toujours quand il s'agit de passer d'un cas d'école simplifié à une application réelle.
En fait c'est pire que ça, car chaque fiche peut avoir sa propre structure. Il peut y avoir plusieurs textes, plusieurs images (ou aucune), un titre (ou pas). C'est pourquoi j'envisage de les stocker dans des NSDictionnary ou des NSArray, plutôt que dans une structure bien définie.
Je présume. Je vais essayer de lire quelques tutos sur CoreData pour en comprendre les bases.
Le plus compliqué va être de jongler avec les fichiers de données. Pour le reste c'est plus facile.
Un piste qui peut être envisagée c'est CloudKit.
Tu mets tout dans une base publique (pas accessible pour autant, plutôt commune que publique mais c'est le nom donné par Apple).
Une collection avec toutes les herbes, un attribut pour dire de quelle collection l'herbe vient.
- Quand tu démarre l'appli la première fois tu t'arrange pour fetcher tout ce que l'utilisateur a le droit d'avoir. (ou pas tu peux faire juste du caching, c'est à toi de voir)
- L'utilisateur achète une catégorie en plus ? Tu fetch le contenu.
Avec ce genre de vieux schema EA (affreusement faux mais ça donne une idée) on se rend mieux compte :
Avec CloudKit tu n'es pas tributaire d'iOS vu qu'il y a une API JavaScript et tu peux utiliser n'importe quelle solution de persistence sur les machines (CoreData, Realm, SQLite pur, etc...)
* se gratte la tête * Je vais essayer un bon vieux fichier binaire, pour commencer.
Comme tu veux
Regarde peut-être NSCoding pour te faire une idée histoire que la serialisation / deserialisation soit automatisée.
100x plus simple à appréhender que CoreData, et bien plus naturel.
- tu crées des objets comme tu créerais n'importe quel NSObject de base, pas comme en CoreData ou faut passer par un contexte et déjà comprendre ce que c'est que ce bidule de contexte, là en Realm tu le crées comme si c'était n'importe quel autre objet
- quand tu veux sauver un objet en base tu fais ça dans un bloc "write" : " realm.write { realm.add(tonObjet) } "
- quand tu veux récupérer tous tes objects tu fais " realm.objects(TaClasse) "
- si tu ne veux récupérer que l'objet qui a le nom unNom, tu fais " realm.objects(TaClasse).filter("nom = %@, unNom) . Et ça ne va pas lire tout ton fichier mais juste trouver l'entrée que tu cherches. Donc c'est ce que tu cherches dans ta question d'origine, n'aller lire que l'entrée qui va bien et pas tout le fichier.
Intéressant. Mais cela requiert iOS 8 minimum. Je préfère quelque chose qui puisse tourner sous iOS 7, pour être compatible avec un iPhone 4.
Finalement pourquoi ne pas utiliser une base sqlite pour les fichiers disponible en téléchargement ainsi pour la base de données locale ? (tu pourrais utiliser un ATTACH DATABASE pour ne pas avoir à merger les bases différentes bases).
Format simple, multi plateforme, accessible en hors-ligne et pas plus compliqué que d'avoir à gérer CoreData, un fichier binaire ou autre (surtout avec les Framework qui excitent).
+1
D'autant que tu peux créer facilement un objet Realm à partir d'un dictionnaire.
Pour faire ce que tu veux, je dirais 5-6 lignes de code.
Si le numéro d'entrée dans le tableau est vraiment important pour toi, tu peux le définir comme clé primaire de ton objet, puis utiliser la méthode objectForPrimaryKey: pour y accéder directement.