NSUserDefaults sur le simulateur

guittonewsguittonews Membre
22:12 modifié dans API UIKit #1
Bonjour à  tous :)

J'avance de mieux en mieux et me retrouve confronter à  de moins en moins de problème (même si comme tout débutant je pense que la qualité de mon code en prend un coup...les reflexions philosophiques lié au code viendront avec l'experience :) ).

Il n'empêche que je suis confronter à  un problème avec les NSUserDefaults :
Je lance mon appli, je me log, je sauvegarde mes infos no problemo.
Je ferme l'appli (pas le simulateur!) je réouvre et la plsu rien....C'est grave docteur?

Je mettrai plus d'info si jamais ce n'est pas le comportement normal du simulateur :)

Merci à  vous tous :)

Réponses

  • Philippe49Philippe49 Membre
    22:12 modifié #2
    Pas normal, tu dois retrouver tes infos en l'état.
  • Eric P.Eric P. Membre
    22:12 modifié #3
    Peut-être que le problème est lié à  l'utilisation du point au lieu de la virgule pour les nombres décimaux dans le simulateur et à  la façon de stocker les données.

    Juste une idée comme ça.

    Eric
  • guittonewsguittonews Membre
    22:12 modifié #4
    Merci pour vos réponses :)

    J'ai du coup regardé un peu plus en profondeur les exemple de la doc (drilldown et apppreferences) et je n'ai pas bien vu ce que je faisais de différent...

    du coup je vous montre ce que j'ai fait :


    A un moment donné j'enregistre des informations relatives au login
    <br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NSMutableDictionary *loginValues=[NSMutableDictionary dictionary];<br />		[loginValues setObject:pseudo forKey:@&quot;pseudo&quot;];<br />		[loginValues setObject:password forKey:@&quot;password&quot;];<br />		//[loginValues setObject:[NSKeyedArchiver archivedDataWithRootObject:idUtilisateur] forKey:@&quot;idInscrit&quot;];<br />		[loginValues setObject:idUtilisateur forKey:@&quot;idInscrit&quot;];<br />		<br />		[[NSUserDefaults standardUserDefaults] registerDefaults:loginValues];<br />		[[NSUserDefaults standardUserDefaults] synchronize];<br />
    



    A "l'autre bout" de mon application je met une trace (pas dans la console parce que au "re lancage" de l'appli elle n'apparait plus) :

    <br /><br />		//self.title=[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:@&quot;idInscrit&quot;]];<br />		self.title=[[NSUserDefaults standardUserDefaults] objectForKey:@&quot;idInscrit&quot;];<br />
    


    Quand je me log, je vais voir ma trace ca marche nikel (ca m'affiche l'id). Je quitte l'appli (sans fermer le simulateur) et la relance. vais voir ma trace et la plus rien :/

    Why?  :'(

    Merci :)

  • Philippe49Philippe49 Membre
    mars 2009 modifié #5
    Pour observer l'état du fichier tu peux faire
    NSLog(@%@",[standardUserDefaults dictionaryRepresentation]);

    Autrement un petit essai qui marche (un view controller avec deux UITextField, le contenu du textField 1 est enregistré dans les defaults, et reporté à  l'ouverture dans le textField 2)   :

    + (void)initialize{	<br />	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];<br />	NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@&quot;Machin&quot; forKey:@&quot;content&quot;];	<br />	[defaults registerDefaults:appDefaults];<br />}<br /><br />- (void)viewDidLoad {<br />	[super viewDidLoad];<br />	NSUserDefaults * standardUserDefaults=[NSUserDefaults standardUserDefaults];<br />	NSLog(@&quot;%@&quot;,[standardUserDefaults dictionaryRepresentation]);<br />	textField2.text=[standardUserDefaults stringForKey:@&quot;content&quot;];<br />	<br />	[textField1 becomeFirstResponder];<br />}<br /> <br /><br />-(BOOL) textFieldShouldReturn:(UITextField *) aTextField {<br />	NSUserDefaults * standardUserDefaults=[NSUserDefaults standardUserDefaults];<br />	[standardUserDefaults setObject:[textField1 text] forKey:@&quot;content&quot;];<br />	[standardUserDefaults synchronize];<br />	NSLog(@&quot;%@&quot;,[textField1 text]);<br />	[textField1 resignFirstResponder];<br />	return YES;<br />}<br />
    
  • Philippe49Philippe49 Membre
    22:12 modifié #6
    Avec ce genre de fichiers, il faut de temps en temps "nettoyer" parce que la synchronisation avec XCode n'est pas très simple à  comprendre /
    - Supprimer le Build
    - Supprimer l'appli dans le simulateur
    - et des fois que, Build > Clean All Targets 
  • guittonewsguittonews Membre
    22:12 modifié #7
    Merci de prendre le temps de me répondre :)

    Bon je crois que je vais me replonger dans la doc parce que je ne vois pas trop ce que je fais de différent par rapport à  toi non plus...La seul diff viendrait du coté de ta méthode initialize...Mais je ne vois pas avec quoi initialiser mon truc...

    Je vais essayer d'expliquer ce que j'ai compris, vous me reprenez si je me trompe.


    //set
    Je créé un Mutable.
    Je le rempli.
    Je le set dans UserDefaults avec une key.
    Je synchronise.

    //get (dans la meme session)
    Je chope mes UserDefaults
    Je get mon objet avec la key.
    /*pour moi ca marche jusque là */

    //get (dans une autre session)
    Je chope mes UserDefaults
    Je get mon objet avec la key
    /*là  ça chie*/

    Dans les différents exemples que j'ai pu voir (doc/philippe49), il y a une phase "d'initialisation" des UserDefaults au lancement de l'appli. Est elle obligatoire?

    Thx a lot.

    Ptite question hors sujet : on peut voir les log meme pour un "relançage" de l'appli?


  • CéroceCéroce Membre, Modérateur
    mars 2009 modifié #8
    idInscrit est bien un objet ?

    Je pose la question, parce que j'aurais plutôt tendance à  utiliser un int pour stocker un id, et le convertir en NSNumber au dernier moment.
  • Philippe49Philippe49 Membre
    mars 2009 modifié #9
    dans 1237976285:

    Dans les différents exemples que j'ai pu voir (doc/philippe49), il y a une phase "d'initialisation" des UserDefaults au lancement de l'appli. Est elle obligatoire?

    Non


    dans 1237976285:

    Ptite question hors sujet : on peut voir les log meme pour un "relançage" de l'appli?

    Dans la console (Application/Utilitaires) , system.log

  • Philippe49Philippe49 Membre
    22:12 modifié #10
    dans 1237976442:

    idInscrit est bien un objet ?

    Je pose la question, parce que j'aurais plutôt tendance à  utiliser un int pour stocker un id, et le convertir en NSNumber au dernier moment.


    Avec un NSInteger , on utilise setInteger: forKey:
  • Philippe49Philippe49 Membre
    22:12 modifié #11
    dans 1237976285:

    //get (dans la meme session)
    Je chope mes UserDefaults
    Je get mon objet avec la key.
    /*pour moi ca marche jusque là */

    //get (dans une autre session)
    Je chope mes UserDefaults
    Je get mon objet avec la key
    /*là  ça chie*/


    C'est donc que tu réécris dans ce fichier ...
    - En cours de fonctionnement de ton appli ?
    - Dans applicationWillTerminate: ?
  • Philippe49Philippe49 Membre
    22:12 modifié #12
    Vérifie aussi ce que dit Ceroce

    Dans [loginValues setObject:idUtilisateur forKey:@idInscrit]; idUtilisateur ne peut pas être un int.
    Il faudrait mettre [loginValues setObject:[NSNumber numberWithInt:idUtilisateur] forKey:@idInscrit];
  • guittonewsguittonews Membre
    22:12 modifié #13

    Citation de: guittonews le Aujourd'hui à  11:18
    Ptite question hors sujet : on peut voir les log meme pour un "relançage" de l'appli?
    Dans la console (Application/Utilitaires) , system.log

    Merci je regarde ca :)




    Citation de: guittonews le Aujourd'hui à  11:18
    //get (dans la meme session)
    Je chope mes UserDefaults
    Je get mon objet avec la key.
    /*pour moi ca marche jusque là */

    //get (dans une autre session)
    Je chope mes UserDefaults
    Je get mon objet avec la key
    /*là  ça chie*/

    C'est donc que tu réécris dans ce fichier ...
    - En cours de fonctionnement de ton appli ?
    - Dans applicationWillTerminate: ?


    A priori c'est le seul endroit dans mon code ou JE touche aux userdefaults :/ (je viens de mettre un log dans applicationWillTerminate et j'ai toujours mes données...)


    Par rapport à  ce que dit Ceroce, en effet en terme d'optimisation je devrais le faire. Cepandant un Int est aussi un objet donc en brut je devrais récup mon objet (quel qu'il soit) dans ma nouvelle session...

  • Philippe49Philippe49 Membre
    22:12 modifié #14
    dans 1237977831:

    Par rapport à  ce que dit Ceroce, en effet en terme d'optimisation je devrais le faire. Cepandant un Int est aussi un objet donc en brut je devrais récup mon objet (quel qu'il soit) dans ma nouvelle session...

    Ah pas du tout, un objet c'est un pointeur. C'est fondamental d'encapsuler l'int dans un objet pour pouvoir le stocker dans un dictionnaire.
  • guittonewsguittonews Membre
    mars 2009 modifié #15
    Ok, je vais regarder ca...

    Je pensais que Int ou String héritaient de Object donc que à  partir de ce constat là  je pouvais les stoquer en objet et qu'il n'y avait pas de problèmes (et ca marchait dans la même session donc...). Tout en étant d'accord que c'est crade!! Mais bon XP...coder crade mais rapidement puis faire du refactoring :)

    Je fais ces modifs là  entre midi et deux et vous tiens au courant. Merci :)
  • guittonewsguittonews Membre
    22:12 modifié #16
    Le problème est réglé pour les id, mes id son bien des chaines de caractere (je les récupere d'un xml et les renvoi dans du xml et ne fais rien d'autre avec.). donc je dois bien utilisé setObject: forKey:...
  • Philippe49Philippe49 Membre
    22:12 modifié #17
    Récupérés de xml en NString * ou en char * ?
    Il faut que ce soit des NSString *
  • guittonewsguittonews Membre
    22:12 modifié #18
    Ce sont bien des NSString * ...

    Je suis en train de tracer encore plus ce queje fais pour essayer de voir à  quel moment ca chie vraiment....
  • guittonewsguittonews Membre
    mars 2009 modifié #19
    bon ben derniers test plus que bizar :/

    Je log mes UserDefaults dans mon applicationWillterminate : resultat j'ai mes données à  ce moment là .

    Je réouvre l'appli : je trace dans applicationDidFinishLaunching: plus rien....
  • Philippe49Philippe49 Membre
    22:12 modifié #20
    Essaye de stocker une valeur qui ne provient pas de ton XML (une NSString * constante : @truc) dans l'initialisation de ton UserDefaults

  • guittonewsguittonews Membre
    22:12 modifié #21
    C'est fait, je stock aussi le login qui lui provient d'un textfield : même constat. Strange...
  • AliGatorAliGator Membre, Modérateur
    22:12 modifié #22
    Répare les autorisations de ton mac + vérifie les droits d'accès dans "~/Library/Application Support/iPhone Simulator" : c'est peut-être un problème d'accès en lecture/écriture de ces dossiers en particulier qui fait qu'il n'arrive pas à  écrire dans "~/Library/Application Support/iPhone Simulator/User/Library/Preferences/" ?

    Après un "synchronize", vérifie aussi que le plist des préférences est créé dans ce dossier, et si oui regarde ce qu'il contient, voir s'il est vide ou s'il a tes informations, pour savoir si c'est l'enregistrement sur disque qui débloque, ou la lecture depuis le disque...
  • guittonewsguittonews Membre
    mars 2009 modifié #23
    Je vais regarder dans cette direction. Ce qui m'étonne c'est que les applications de "démo" fournis avec la docs apple fonctionnent (avec le UserDefault)...Je doit merder quelque part. Je vais rechecker mon code :/

    Edit : je n'ai pas le dossier iPhone simulator dans application support
  • guittonewsguittonews Membre
    22:12 modifié #24
    bon ben je ne sais pas trop pourquoi c'est tombé en marche :D

    Je pense que je n'utilisé pas la bonne méthode pour sauvegarder dans mes UserDefaults, après savoir pourquoi cela marchait dans la "même" session mais non persistent...i don't know.

    voilà  ce que je faisait :

    <br />		[[NSUserDefaults standardUserDefaults] registerDefaults:loginValues];<br />
    


    et voila ce que je fais (je rempalce la ligne du dessus par celle ci) :

    <br /><br />		[[NSUserDefaults standardUserDefaults] setObject:loginValues forKey:@&quot;credential&quot;];<br />
    




    Ce qu'il y a un peu au dessus dans le code se trouve en premeire page du fil de discussion :) (pour les curieux :) )

    Je suis désolé de vous avoir fait perdre du temps :/ et vous remerci :)

    a (très) bientôt !!
  • NoNo Membre
    22:12 modifié #25
    dans 1237988997:

    voilà  ce que je faisait :
    <br />		[[NSUserDefaults standardUserDefaults] registerDefaults:loginValues];<br />
    

    et voila ce que je fais (je rempalce la ligne du dessus par celle ci) :
    <br /><br />		[[NSUserDefaults standardUserDefaults] setObject:loginValues forKey:@&quot;credential&quot;];<br />
    



    Pas étonnant.
    C'est on-ne-peut-plus-explicite dans la doc : la méthode registerDefaults: ajoute le dictionnaire passé en paramètre aux userDefaults de l'appli, mais en mémoire. Donc, il n'y a pas d'écriture sur le disque.

    Cela sert par exemple à  "concaténer" le contenu d'un plist quelconque avec les véritables userDefaults lus depauis le disque.

    The contents of the registration domain are not written to disk; you need to call this method each time your application starts. You can place a plist file in the application's Resources directory and call registerDefaults: with the contents that you read in from that file
  • guittonewsguittonews Membre
    mars 2009 modifié #26
    bah maintenant que tu le dis....je m'autoflagelle  >:)


    Petite quesiton au passage : disons que je stock un mutabledictionary.
    Hop setObject: forkey: bim bam tout va bien, j'enchaine je veux récup mon mutabledictionary pour le modifier et la patatrak.

    Puis-je récuperer un mutableDictionary de mon UserDefault?

    Pas la peine de me sortir un RTFM :D, j'ai bien vu ça :

    Values returned from NSUserDefaults are immutable, even if you set a mutable object as the value. For example, if you set a mutable string as the value for "MyStringDefault", the string you later retrieve using stringForKey: will be immutable.




    Merciiiii
  • AliGatorAliGator Membre, Modérateur
    mars 2009 modifié #27
    Tu récupères un NSDictionary, et si tu veux le rendre mutable tu demandes une "mutableCopy" (cf le NSMutableCopying protocol, implémenté par NSDictionary, NSArray, ...) et tu release l'original immutable ensuite.

    NSDictionary* dict = [[NSUserDefaults ...] ...];
    NSMutableDictionary* mdict = [dict mutableCopy];
    [dict release];
    // do sthg with mdict
  • guittonewsguittonews Membre
    22:12 modifié #28
    hiiihaaaaaaaa


    Merci merci merci :) :) :)  :p :p :p :p :p :(renaud):
  • guittonewsguittonews Membre
    22:12 modifié #29
    Bon jour à  tous, je post à  la suite de ce sujet parce que...c'est la suite de mon problème :D

    Voilà , je bute contre un mur ( :crackboom:- ) et malgré quelque dizaine de passage en mode débug, et un tracage exhaustif dans la console je ne vois toujours pas....

    D'abord le code j'explique ensuite ce que je fais (ou ai voulu faire...)

    - (void)saveAction:(id)sender<br />{<br /><br />	<br />	<br />	<br />	//------recup speedsmos<br />	NSDictionary *pref= [[NSUserDefaults standardUserDefaults] objectForKey:@&quot;speedsmos&quot;];<br />	NSMutableDictionary* speedsmos = [pref mutableCopy];<br />	[pref release];<br />	//[speedsmos setObject:visageDefault forKey:@&quot;Visage&quot;];<br />	//------recup visage<br />	NSDictionary *pref1= [speedsmos objectForKey:@&quot;Visage&quot;];<br />	NSMutableDictionary* visage = [pref1 mutableCopy];<br />	[pref1 release];<br />	//------set du texte dans visage<br />	[visage setObject:textViewD.text forKey:@&quot;Cheveux&quot;];<br />	//------set du visage dans speedsmos<br />	[speedsmos setObject:visage forKey:@&quot;Visage&quot;];<br />	//------set de speedsmos dans userdefaults<br />	[[NSUserDefaults standardUserDefaults] setObject:speedsmos	forKey:@&quot;speedsmos&quot;];<br />	[speedsmos release];<br />	[[NSUserDefaults standardUserDefaults] synchronize];<br />	NSLog(@&quot;%@&quot;,[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);<br />	<br />	<br />	[textViewD resignFirstResponder];<br />	self.navigationItem.rightBarButtonItem = nil;<br />}<br />
    


    J'ai un dictionary dans mes usersdefaults, qui contient d'autre dictionary (en gros mon arborescence). Puis j'arrive sur une vue qui me permet de mettre à  jour le dernier niveau de l'arborescence (ici codé en dur au niveau de : "set du texte dans visage").

    Le log que j'ai laissé ici m'affiche bien mon dictionary au complet avec ma modif. Cependant j'ai un exec bad acces sur ma derniere ligne (pour virer le boutton "done").

    Là  où c'est louche c'est que si je vire tout mon code qui traite avec les usersdefaults ca passe nikel o_0

    Une piste? un conseil? Je suis preneur :)

    Merci à  tous et bon début de semaine :)
  • NoNo Membre
    avril 2009 modifié #30
    Les 2 release en rouge sont plantogènes :
    [tt]
    - (void)saveAction:(id)sender
    {
       //
    recup speedsmos
       NSDictionary *pref= [[NSUserDefaults standardUserDefaults] objectForKey:@speedsmos];
       NSMutableDictionary* speedsmos = [pref mutableCopy];
       [pref release];
       //[speedsmos setObject:visageDefault forKey:@Visage];
       //
    recup visage
       NSDictionary *pref1= [speedsmos objectForKey:@Visage];
       NSMutableDictionary* visage = [pref1 mutableCopy];
       [pref1 release];
       //
    set du texte dans visage
       [visage setObject:textViewD.text forKey:@Cheveux];
       //
    set du visage dans speedsmos
       [speedsmos setObject:visage forKey:@Visage];
       //
    set de speedsmos dans userdefaults
       [[NSUserDefaults standardUserDefaults] setObject:speedsmos   forKey:@speedsmos];
       [speedsmos release];
       [[NSUserDefaults standardUserDefaults] synchronize];
       NSLog(@%@",[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]);
       [textViewD resignFirstResponder];
       self.navigationItem.rightBarButtonItem = nil;
    }
    [/tt]

    Un rappel sur les release : on ne doit faire un release sur un objet que si on l'a précédemment créé dans son code (donc issu d'un alloc/init, d'un new ou d'un copy).
    pref et pref1 sont des objets en autorelease (car non créés par aucune des méthodes précédentes).
    Ils vont donc recevoir un release implicite un peu plus tard (lors du vidage de l'autorelease pool, généralement).
    Si toi tu fais aussi un release, alors le premier va détruire effectivement l'objet, et le second va tenter de détruire un objet qui n'existe plus, donc PLANTAGE.
  • guittonewsguittonews Membre
    22:12 modifié #31
    comment dire.....MERCIIIIIIIIIIIIIIIIIIIIIII

    'tin que ferais - je sans vous tous!!!


    tournée généraaaleeeeeee :  <3 :p :p :p :p :p <3
Connectez-vous ou Inscrivez-vous pour répondre.