Meilleure stratégie (ou macros pour simplifier?) pour une structure en arbre
AliGator
Membre, Modérateur
Bonjour à tous,
Voilà j'ai besoin dans mon modèle d'avoir une structure, hiérarchisée pour plus de clareté, représentant un objet.
Par exemple on va dire qu'il s'agit d'un logiciel, qui a comme attributs un auteur (nom, prénom, date de naissance), une description (nom, version, date), une société (nom, statut, adresse), une plateforme. (En réalité ma structure est bien plus complexe et a bien plus d'attributs)
L'idée est de structurer mes données, plutôt que d'avoir un gros NSObject qui contienne toutes ces données à plat.
Mais ma question, c'est comment générer les classes pour cette structure de données sans avoir 1500 lignes de glue code rébarbatif ?
Besoins souhaités :
- Structure facilement parcourrable par code (notation pointée des @property souhaitée)
- Structure sérialisable/archivable (dans un plist ou du genre)
- KVC-compliant, en tout cas supportant les KeyPaths
Solutions possibles :
C'est cette dernière vers laquelle je me suis dirigée, en déclarant mes vi en @property. Donc en gros j'ai les classes Auteur, Description, Societe, et une classe Logiciel qui contient une vi "NSString* plateforme" et une vi Auteur*, une Description* et une Societe*.
Mais le truc c'est que du coup faut implémenter plein de trucs rébarbatifs (init, dealloc, initWithCoder, encodeWithCoder, ...)
Du coup je me demandais si vous aviez des idées d'alternatives plus simples à mettre en oeuvre (non pas que le code soit compliqué, mais plutôt lassant en fait).
Ou alors des idées d'astuces, genre macros preprocesseur à la #define, pour éviter de répéter tout le temps du code qui se ressemble...
- Dans la déclaration des vi
- Dans la déclaration des @property associées
- Dans le init quand j'alloc les classes "conteneur" (mais pas les feuilles de ma structure, pas besoin ça)
- Dans le dealloc quand je release mes vi
- Dans le encodeWithCoder
- Dans le initWithCoder
---> Dans chacune de ces méthodes on met un peu toujours les mêmes choses, et on boucle sur les variables d'instance, c'est rébarbatif.
Mais je ne vois pas comment, avec une macro ou autre (pour aussi que si je modifie ma structure j'ai pas tout à refaire au risque d'oublier un truc), simplifier le codage de tout ça ? Genre
Voilà , si vous avez des idées... elles sont toutes bienvenues
Merci d'avance
PS : C'est pour iPhone, donc pas de CoreData (même si je sais pas si ça aurait été adapté, mais au moins ça coupe court à la possibilité ^^)
Voilà j'ai besoin dans mon modèle d'avoir une structure, hiérarchisée pour plus de clareté, représentant un objet.
Par exemple on va dire qu'il s'agit d'un logiciel, qui a comme attributs un auteur (nom, prénom, date de naissance), une description (nom, version, date), une société (nom, statut, adresse), une plateforme. (En réalité ma structure est bien plus complexe et a bien plus d'attributs)
L'idée est de structurer mes données, plutôt que d'avoir un gros NSObject qui contienne toutes ces données à plat.
Mais ma question, c'est comment générer les classes pour cette structure de données sans avoir 1500 lignes de glue code rébarbatif ?
Besoins souhaités :
- Structure facilement parcourrable par code (notation pointée des @property souhaitée)
- Structure sérialisable/archivable (dans un plist ou du genre)
- KVC-compliant, en tout cas supportant les KeyPaths
Solutions possibles :
- un bête NSDictionary : c'est KVC, facilement sérialisable... mais on peut enregistrer un peu n'importe quoi dedans donc côté error-checking des clés c'est pas terrible. Et côté facilement parcourable c'est pas ça : on peut bien faire un [tt][dict valueForKeyPath:@machin.truc.bidule][/tt] mais je préférerais qd mm une notation directe dict.machin.truc.bidule
- Une classe perso dérivant de NSObject avec les variables d'instance qui vont bien
C'est cette dernière vers laquelle je me suis dirigée, en déclarant mes vi en @property. Donc en gros j'ai les classes Auteur, Description, Societe, et une classe Logiciel qui contient une vi "NSString* plateforme" et une vi Auteur*, une Description* et une Societe*.
Mais le truc c'est que du coup faut implémenter plein de trucs rébarbatifs (init, dealloc, initWithCoder, encodeWithCoder, ...)
Du coup je me demandais si vous aviez des idées d'alternatives plus simples à mettre en oeuvre (non pas que le code soit compliqué, mais plutôt lassant en fait).
Ou alors des idées d'astuces, genre macros preprocesseur à la #define, pour éviter de répéter tout le temps du code qui se ressemble...
- Dans la déclaration des vi
- Dans la déclaration des @property associées
- Dans le init quand j'alloc les classes "conteneur" (mais pas les feuilles de ma structure, pas besoin ça)
- Dans le dealloc quand je release mes vi
- Dans le encodeWithCoder
- Dans le initWithCoder
---> Dans chacune de ces méthodes on met un peu toujours les mêmes choses, et on boucle sur les variables d'instance, c'est rébarbatif.
Mais je ne vois pas comment, avec une macro ou autre (pour aussi que si je modifie ma structure j'ai pas tout à refaire au risque d'oublier un truc), simplifier le codage de tout ça ? Genre
GENERATE_CLASS( Auteur , (NSString,nom),(NSString,prenom),(NSDate,dateNaissance) );<br />// et hop magique ça me génère @interface et @implementation complète avec les variables d'instance citées et leurs types, en créant le init/dealloc/encodeWithCoder/initWithCoder qui vont bien
Bon je rêve peut-être un peu c'est sans doute utopiste, mais si vous avez au moins des astuces... je suis prenneur, vu la taille de ma structure à générer.Voilà , si vous avez des idées... elles sont toutes bienvenues
Merci d'avance
PS : C'est pour iPhone, donc pas de CoreData (même si je sais pas si ça aurait été adapté, mais au moins ça coupe court à la possibilité ^^)
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
Un mix des deux :P
Une classe dérivée de NSMutableDictionary qui teste les clés en entrée, avec éventuellement des ajouts de properties pour les clés courantes.
Bah à part les subtilités sur les macros, je vois pas trop. Tu connais le # et le ## ?
#TOTO génère la chaà®ne "TOTO" au préprocessing
et ## permet de concétaner.
et les macros supportent le __VA_ARGS__ http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html
Rien de bien neuf, mais si on connaà®t pas...
PS : C'est pour iPhone, donc pas de CoreData (même si je sais pas si ça aurait été adapté, mais au moins ça coupe court à la possibilité ^^)
Ah me semble bien que le SDK 3.0 contient du CoreData :-D
+
Chacha
Et NSXMLDocument ?
ça semble répondre à ton cahier des charges.
PS : C'est pour iPhone, donc pas de NSXMLDocument.
C'est pas idiot... j'y ai pensé à un moment, mais me suis dit que quand je déclarais mes properties, il faudrait que j'écrive moi-même les setters/getters desdites propriétés pour faire un setValue:forKey et un valueForKey à la place... donc j'avais oublié cette possibilité. Mais vu comme finalement les autres possibilités impliquent aussi de pisser pas mal de code... finalement ça pouraà®t être un bon compromis.
Un truc comme ça donc :
J'ai rajouté le init pour pré-créer ma structure de dictionnaires quand même, pour que si je fais [soft setValue:@moi forKeyPath:@auteur.nom] il fonctionne bien (car si auteur est nil au lieu d'être un Auteur* existant, setValue:forKeyPath: marchera pas)... donc si je me suis pas gourré dans mon init, il va me créer un Auteur* (soit un NSMutableDictionary) qu'il va affecter à la clé "auteur" du dictionaire principal "Logiciel", pareil pour description et societe, ce qui me permettra d'utiliser setValue:forKeyPath: sans soucis...
Et du coup pas besoin d'implémenter NSCopying, c'est déjà tout prêt, ni besoin de déclarer des variables d'instance qui font redondant avec les @property puisqu'on utilise un NSDictionary pour les stocker.
Vous en pensez quoi, de cette solution ? (pas encore testée sur un vrai projet) ?
Sinon au lieu de faire par héritage, je pensais aussi faire par wrapping : Auteur dériverait de NSObject, mais contiendrait une vi unique NSMutableDictionary* data. Et après on reprend le même principe. Avantage, pas de risque d'appeler les méthodes de NSMutableDictionary sur mon Auteur. Inconvénient, faut implémenter NSCopying, mais au moins il est générique, il suffit d'encoder data pour que ça sérialise tout l'objet, donc c'est "macrotisable".
Je sais pas lequel est le plus propre...
En effet sinon le XML c'est pas top car sur iPhone, pas de parsing DOM du XML, que du parsing SAX, donc ça va pas le faire.
Alors pour info, voilà comment j'ai fini par implémenté la chose, en suivant vos conseils :
Voilà le début de mon .h (macros et classe de base) :
Et le début de mon .m (macros et classe de base) : Ces deux outils (les macros et la classe StructuredObject) me permettent de déclarer ensuite mes classes ainsi (dans le même .h et .m en l'occurrence) : Avantage, c'est propre, une fois mes macros et ma classe de base StructuralObject prête, toutes mes classes ressemblent à la classe Person citée ici en exemple... et que comme vous pouvez le constater, c'est exactement le même contenu mis dans le @interface et le @implementation, permettant de faire direct un copier/coller C'est la définition différente des macros dans le .h et le .m qui fait tout le travail.
---
Et en plus ça permet tout de même des cas particuliers : par exemple j'ai une classe EntityGroup (que j'ai simplifiée ici) qui gère entre autres un CGPoint... variable qui ne peut pas être mise dans le dictionnaire. Du coup soit je l'encodais en NSDictionary ou NSValue pour le stocker... soit je mettais une variable d'instance pour ce cas particulier, ce que j'ai fini par faire, De plus cette classe est un bon exemple aussi car elle contient des v.i. elles-mêmes de type StructuralObject (enfin des sous-classes), qu'il faut donc penser à initialiser : Et donc pour l'implémentation : Voilà , ça m'a l'air pas mal comme solution !
Gros avantage : c'est très facile à implémenter, et vu le nombre de classes du genre que j'ai dans ma structure hiérarchique, c'est un point important.
Quand je veux déclarer un nouveau "groupe de propriétés" à utiliser dans ma structure, j'écris [tt]@interface MonType : StructuredObject {}[/tt] puis je liste toutes les propriétés que je veux avec [tt]PROP_OBJ(type,var)[/tt], et je termine avec [tt]@end[/tt]... Et ensuite j'ai simplement à copier/coller exactement les mêmes lignes dans le @implémentation Comme on le voit pour le cas de la classe "Person"Â
Voilà , ça devient du coup bien plus sympathique que ce vers quoi j'étais parti initialement, donc merci de vos suggestions
(PS : Je n'ai pas encore testé le NSCoding même si je l'ai implémenté dans ma classe StructuredObject, faut que je vérifie que ça marche bien)
Avec le recul, que penses-tu de ta manière de faire ? Est-ce qu'elle correspond bien à ce que tu voulais, est-ce réellement plus pratique ?
En tout cas je garde l'idée dans un coin, cela peut être très utile si on a beaucoup de classes du genre à créer.