NSUserDefaults

6ix

Membre confirmé
12 Juillet 2005
28
0
38
Bonjour,

Je squatte un peu le forum ces temps... :rose:
Je désire enregistrer certaines variables de mon programme en tant que préférences avec NSUserDefaults, et j'ai suivi le sujet à ce propos sur Project:Omega.
Et puis voilà, arrivé à la fin, cela ne marche pas, et je me rends compte que les NSUserDefaults ne peuvent que stoquer des types dits "property list" (NSDate,NSData,NSNumber,NSArray,NSDictionary,NSString), alors que moi j'essaie de stoquer un NSArray, ok, mais qui contient des objets que j'ai moi-même définis (d'où le problème je suppose...).
NSArray -------- Article -------- date (variables d'instance)
|_______ nom
|_______ prix

Donc je pourrais:
1) supprimer ma classe perso, et faire en sorte que mon NSArray contienne des NSMutableDictionnary; pourtant, en possédant une classe séparée, je trouve le tout plus clair (et plus orienté POO, isn't it?), et surtout, grâce à certaines méthédes définies dans cette classe, cela m'évite de passer à chaque fois par tel ou tel élément du dictionary
2) garder ma structure actuelle, et, au moment d'enregistrer et récupérer mes éléments avec NSUserDefaults, convertir chaque Article en un NSMutableDictionnary; pourquoi pas me dis-je, c'est peut-être encore le mieux, même si cela rajouterait "bêtement" du code en copiant cette structure
3) existe-il un autre moyen...?

N'étant qu'au début de ma "Cocoa-experience", je cherche sur le net et dans des bouquins, sans pourtant forcément trouver une solution recommandée ou de réponse claire, je demande donc l'avis de ceux qui en ont l'habitude.
Merci bien
 
C'est vrai que les NSUserDefaults enregiste en XML que les données des types que tu cites.
Je pense que le plus simple est de redéfinir tes propriétés dans ces types là pour creer le dictionnaires des parametres.

Mais j'ai l'impression que ce que tu veux enregistrer n'est pas des préférences utilisateur, mais plutot des données qui devraient être dans un fichier (que tu enregistre et que tu ouvres). Pour cela, le libre Cocoa par la pratique le décrit très bien, en expliquant le fonctionnement des NSCoder.
Mais il y a encore plus simple que les NSCoder: c'est CoreData. Je ne suis pas chez moi, et ne peux donc pas te données plus d'info là dessus, mais c'est très puissant et relativement facile à mettre en oeuvre (il y a un tuto en anglais sur un site. Je retrouve le nom ce soir)
 
Oui effectivement, cela dépasse un peu les simples préférences...
En fait, il y a plusieurs éléments différents que j'aimerais ainsi enregistrer (j'en ai cité qu'un pour exemple):
-de "vraies" préférences, qui ne me posent aucun problème
-des données selon la structure citée plus haut, mais que je considère comme faisant partie des préférences, car remplissant la fonction de préférences (donc peu importantes, finalement); à noter que je suis en train de convertir cette structure sous forme de NSDictionary
-finalement de pures données, avec la structure citée avant; ayant suivi le tuto de Project:Omega, où mis à part mon problème les choses sont assez simples, je ne me suis même pas vraiment posé la question d'une autre manière de procéder que NSUserDefaults... Mais il est évident qu'il y a d'autres possibilités, tout en gardant du XML, je vais donc regarder du côté de NSCoder. Je reste cependant ouvert à tte information, même si je vais bien sûr me renseigner là-dessus.

Franchement, je crois que Cocoa offre tellement de possibilités déjà présentes qui simplifient tellement la vie que j'en oublie de regarder un peu ailleurs et reste focalisé sur une solution... :mad: Merci de m'ouvrir un peu les yeux!
Ca devient bien plus facile quand on utilise les bonnes choses au bon endroit!
 
Je me suis penché du côté de NSCoder et NSArchiver, mais je rencontre qques difficultés.

J'ai une classe Controller, qui a pour variable un NSMutableArray articleList, qui contient des objets Article (classe que j'ai définie moi-même), ayant pour variables d'instance NSCalendarDate *date, NSString *name et float cost (comme mentionné plus haut).
Voilà ce que j'ai fait:
"Article.m":
Bloc de code:
- (void) encodeWithCoder: (NSCoder *)coder
{
	[coder encodeObject: date];
	[coder encodeObject: name];
	[coder encodeValueOfObjCType: @encode(float) at:&cost];
}

- (id) initWithCode:(NSCoder *)coder
{
	if(self = [super init]) {
		[self date:[coder decodeObject]];
		[self name:[coder decodeObject]];
		[coder decodeValueOfObjCType:@encode(float) at:&cost];
	}
	return self;
}
"Controller.m":
Bloc de code:
//sauvegarde des données: articlesList
- (NSData *)dataRepresentationOfType: (NSString *)aType
{
	return [NSArchiver archivedDataWithRootObject:articlesList];
}

- (BOOL) loadDataReprensentation:(NSData *)data ofType:(NSString *)aType
{
	[articlesList release];	//on libère l'ancien tableau
	articlesList =[[NSUnarchiver unarchiveObjectWithData:data] retain];
	[self updateUI];   //méthode définie ailleurs
	return YES;
}

J'ai de plus ajouté un "Document Type"; nom: Document Type (je ne sais pas trop quoi mettre...), Extensions et OSTypes: poly, StoreType: XML, Role: Editor, plus une icône...

1) Ai-je implementé toutes les méthodes utiles? (il me semble que oui...) [Edit: OK]
2) Comment faire pour indiquer le nom et path du fichier sur lequel on enregistre les données? Ayant spécifié StoreType: XML, cela suffit pour que le fichier soit en XML, ou faut-il l'indiquer dans le code?
3) En imaginant que j'aie ajouté plusieurs Document Type, comment indiquer lequel choisir? [Edit: OK]
4) Si je veux qu'un menuItem "Enregistrer" enregistre ces données (car pour le moment cela ne fait rien), vers quelle méthode dois-je lier l'item? (dataRepresentationOfType:(NSString *)aType ?)

Merci pour vos informations
 
Fais gaffe:
Bloc de code:
- (void)encodeWithCode[B][SIZE=3]r[/SIZE][/B]:(NSCoder *)encoder


J'ai de plus ajouté un "Document Type"; nom: Document Type (je ne sais pas trop quoi mettre...), Extensions et OSTypes: poly, StoreType: XML, Role: Editor, plus une icône...

pour Document Type: ce que tu veux, un nom qui décrit le type de document (ex Text Document, Image File, etc) . C'est ce nom qui sera affiché par le finder en mode liste, de plus c'est localisable.

pour extension: ce que tu veux ...
pour OS Type: rien
Store type: rien, c'est pour core data
Class: le nom de ta classe NSDocument qui gère ce type de doc.
Role: editor

Ayant spécifié StoreType: XML, cela suffit pour que le fichier soit en XML, ou faut-il l'indiquer dans le code?
Etant donné que tu archives tes données, ce n'est plus de l'XML.


2) Comment faire pour indiquer le nom et path du fichier sur lequel on enregistre les données?
Si je veux qu'un menuItem "Enregistrer" enregistre ces données (car pour le moment cela ne fait rien), vers quelle méthode dois-je lier l'item? (dataRepresentationOfTypeNSString *)aType ?)

Oui c'est la bonne méthode, et justement aType te permets d'identifier le type de document à sauvegarder (Document Type) en faisant une comparaison sur cette chaine:
if([atype is EqualToString:mad:"Mon type de document")
...

Quant au chemin du fichier, si tu as créé un projet Cocoa Document Based, un panneau devrait s'afficher quand tu cliques sur le menu enregistrer.
 
Merci pour la petite correction, je n'avais pas fait attention!

Donc ce n'est pas du xml... (juste un fichier binaire?) Je suppose donc que pour faire du xml, il faut utiliser les classes cocoa NSXMLqqchose?

Quant au chemin du fichier, si tu as créé un projet Cocoa Document Based, un panneau devrait s'afficher quand tu cliques sur le menu enregistrer.
Justement, non, ce n'est pas un Document Based... Si j'ai bien compris, un Document Based est utilisé pour une application qui traite des documents, style TextEdit, Pages... Mon application est plutôt du style iTunes, qui gère une sorte de bibliothèque (une seule à la fois, même si on pourrait en faire plusieurs); je me suis donc dit qu'il n'était pas nécessaire de faire un projet Cocoa Document Based.

Etant donné que bcp d'exemples sont de ce type, j'ai parfois du mal, comme ici.

Le fait d'assigner à l'item "Enregistrer" la méthode saveDocument: ne donne donc rien, il faut dès lors que je fasse la mienne... mais comment?
 
J'ai oublié un truc:
pour [coder encodeValueOfObjCType: @encode(float) at:&cost];
je ferais:
[coder encodeObject:[NSNumber numberWithFloat:cost];


Donc ce n'est pas du xml... (juste un fichier binaire?)

Si tu veux absolument du xml, il te faut archiver uniquement ta classe perso:
[monDico setObject:[NSArchiver archivedDataWithRootObject:monObjet ] forKey:mad:"Mon Objet"];

Justement, non, ce n'est pas un Document Based...

Tu ne peux plus utiliser NSDocument...

Il faut donc tout gérer à la mano :)
C'est pas très compliqué, mais pas forcément utile :D
 
pour du XML, je pense que le mieux est d'utiliser coreData. Il est possible d'enregistrer en XML ouen binaire très facilement. Je ne suis pas sur que ce soit possible avec les NSCoder standard (du moins, je n'ai pas reussi)

pour un tuto de coreData, voir sur le site de Cocoa Dev Central
c'est comme cela que j'ai commencé
 
Si j'ai bien suivi, mon projet n'était pas Cocoa Document Based, rien n'hérite de NSDocument, ce qui revient à dire que les méthodes que j'ai essayées d'implémenter avant ne me servent à rien...? Réjouissant! :(

J'ai suivi le livre "cocoa par la pratique", et je ne me suis pas bien rendu compte de cette différence (puisque dans le livre il est question d'un projet Cocoa Document Based).

En fait, je ne voudrais pas faire à tout prix du xml, je me dis simplement que d'utiliser ce format standard évite des complications si par la suite je fais des modifications; d'ailleurs, le simple fait d'utiliser un standard est peut-être mieux qu'un format propre à cette application, pour le relire depuis un autre programme ou du style...?

Il faut donc tout gérer à la mano
C'est pas très compliqué, mais pas forcément utile

Qu'entends-tu par "pas forcément utile"? Devrais-je faire une projet Document Based?
"Tout gérer à la mano", grâce à quelles classes (pas forcément xml)?
Je vais toujours regarder du côté de coreData... Je crois qu'il y a un exemple dans les devTools, ça pourra m'aider.
 
Oui merci, je vais regarder ça...

J'aimerais quand même savoir une chose: est-il justifié que je ne fasse pas un projet Document-Based (si dans le concept il ressemble à iTunes: un seul panneau principal, qui s'occuppe d'une "bibliothèque d'éléments"?

Je sors un peu du sujet, mais j'ai l'impression que tous les tutos que je voie sont Document-Based... et je remarque que j'ai encore des problèmes supplémentaires en ajoutant de petites fenêtres/panels annexes (comme des préférences, par ex), alors que tout est assez simple avec un Document-Based.

Si le faire ainsi ne fait que me simplifier la vie, je n'attendrai pas, mais si comme je le pense un projet Document-Based ne s'emploie que pour de réelles applications multi-fenêtres (multi-documents devrais-je dire), j'ai encore du chemin à faire...

En tout cas merci pour tous ces conseils!!
 
Enfin, j'y suis arrivé! J'ai une première version de mon application qui tourne comme je voulais...
Encore merci pour vos infos, j'ai découvert CocoaDevCentral (très bien fait d'ailleurs) que je ne connaissais pas! :)

Finalement, j'ai repris ce que j'ai mentionné plus haut dans le post, j'ai lu et relu la doc Apple, et j'ai réussi à faire qqchose de très correct: c'est du binaire, mais je regarderai pour du xml plus tard.

J'ai fait le tuto de CocoaDev sur les Bindings, super intéressant cette manière de procéder (bien peu de code au final), mais mon problème est que je redéfinissais d'une manière "non standard" les méthodes liées aux NSTableView; à première vue les Bindings ne le permettent pas... enfin, peut-être bien que si, le tuto n'est qu'un aperçu de tout cela, alors plutôt que de chercher encore là-dessus, cela m'a donné des idées pour le faire moi-même... :rolleyes:

J'ai également jeté un coup d'oeil après cela à Core Data, mais là aussi il aurait fallu que je m'y mette plus à fond pour comprendre les subtilités (pour que ça marche avec ce que je voulais faire), et vu que j'avais déjà pratiquement tout...

Cela démontre bien toute les possibilités offertes par Cocoa; limite déroutant pour un débutant!! Faut bien commencer à qque part de toute façon... :zen: