[ Résolu ] Mise en oeuvre d'un NSarray

prepa75prepa75 Membre
avril 2010 modifié dans API AppKit #1
Bonjour à  tous

entre 2 exos de maths j'ai penser à  un truc : pouvoir enregistrer les records de mon jeu dans un fichier de manière à  ce que lorsqu'on le lance à  nouveau le score max reste affiché.

En fouinant sur le forum ainsi que sur la doc apple , je me remet à  vous parsque je n'arrive vraiment pas à  utiliser NSarray.

voici mon code :
<br />	if(score &gt; scoremax)					<br />			{<br />				[best setDoubleValue:score];<br />				scoremax = score;<br />				<br />				char record[1];<br />				record[0] = scoremax ;<br />				printf(&quot;record : %d&#092;n&#092;n&quot;,record[0]);<br />				<br />				[record[0] writeToFile:@&quot;/test.log&quot; atomically:YES];<br />


en gros voila ce que je voudrai faire : mettre le scoremax dans un tableau et le mettre dans un fichier.je sais ça marche pas car "writetofile" est uniquement fait pour un NSarray (si j'ai bien compris la doc  :P ) mais mon problème est que je n'arrive pas à  mettre des chiffres dans un NSarray , dans le livre de Hillegass il utilise que des NSString  :'(

merci par avance  :D

Réponses

  • prepa75prepa75 Membre
    19:36 modifié #2
    Bon j'ai essayer de rechercher tout seul mais en vain, je n'arrive pas à  la coder comme il faut  :'(

    voici mon code :
    <br />if(score &gt; scoremax)					<br />			{<br />				[best setDoubleValue:score];<br />				scoremax = score;<br />			<br />				NSMutableArray *record;<br />				[record addObject:scoremax] ;<br />				NSLog([record objectAtIndex:0]);<br />				<br />				[record writeToFile:@&quot;/test.log&quot; atomically:YES];<br />
    


    le score max ne veut pas rentrer dans le tableau modifiable via addObject et je sais pas ou est le problème c'est possible de mettre un nombre dans un tableau non??
  • mpergandmpergand Membre
    19:36 modifié #3
    <br />NSMutableArray *record;<br />[record addObject:scoremax] ;
    


    Tu fais vraiment n'importe quoi  ::)

    Typiquement pour retrouver des données entre chaque lancement, on utilise User Defaults
  • AliGatorAliGator Membre, Modérateur
    19:36 modifié #4
    dans 1270065879:
    c'est possible de mettre un nombre dans un tableau non??
    Non ce n'est pas possible (du moins pas aussi directement que tu le fais comme un bourrin :P) : les NSArray ne peuvent contenir que des NSObject. D'autant plus que le NSArray retiet les objets qu'il contient (il met un "retain" sur ses objets lorsqu'ils sont ajoutés au NSArray, un "release" quand ils sont supprimés du tableau, etc... cf la doc sur les Container Classes)

    Et là  tu essayes de mettre un int (ou un float ou un double ou un short, je sais pas :P), qui n'est pas du tout un objet.

    Mais bien sûr, la solution existe : il existe la classe NSNumber, qui est faite pour ça justement : elle permet d'encapsuler à  peu près tous les types primitifs représentant des nombres (int, long, float, double, BOOL, ...), ce qui te permet après de les manipuler en tant qu'objets, donc entre autres de les mettre dans un NSArray, ou dans un NSDictionary, ou tout plein d'autres choses.


    Ceci dit en passant, c'est sortir le bazooka pour tuer la mouche que d'utiliser un NSArray pour stocker une seule valeur (ton score max), et pour l'écrire dans un fichier.
    Pour des petites quantités de valeurs à  mémoriser comme ça Utilise NSUserDefaults, qui permet de gérer tout ce qui est préférences et choses du genre pour les stocker de façon pérenne et les récupérer super simplement.
    User Defaults Programming Guide
  • prepa75prepa75 Membre
    19:36 modifié #5
    Merci beaucoup je me disais bien que créer un fichier pour une valeur etais totalement inutile j'ai des restes de C  :P
    dc si j'ai bien compris : NSNumber permet de transformer un nombre( int, double, float, etc...) en un objet.a partir de la on peut le stocker dans NSArray qui reçoit que des objets.je vais potasser la doc des valeurs par defauts

    Bonne soirée à  tous.
  • tabliertablier Membre
    avril 2010 modifié #6
    Bon, si tu es un vrai débutant, jettes un oe“il sur mon vieux tutoriel "Cacao pour débutant" il comprend une utilisation des "User Defaults".
  • prepa75prepa75 Membre
    19:36 modifié #7
    dans 1270119415:

    Bon, si tu es un vrai débutant, jettes un oe“il sur mon vieux tutoriel "Cacao pour débutant" il comprend une utilisation des "User Defaults".


    merci bien , je vais le potasser , parsque là  la doc apple m'a un peu largué... 
  • prepa75prepa75 Membre
    19:36 modifié #8
    bon j'ai essayer de faire un truc mais la sauvergarde ne se fait pas  :'(

    <br />#define raz @&quot;Raz&quot;<br /><br />- (void)applicationDidFinishLaunching:(NSNotification *)notification <br />{&nbsp; &nbsp; <br />&nbsp; &nbsp; defaults = [NSUserDefaults standardUserDefaults] ;&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; scoremax = [defaults integerForKey:raz] ;<br />&nbsp; &nbsp; [best setIntValue:scoremax] ;<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />}<br /><br />- (void)applicationWillTerminate:(NSNotification *)notification<br />{&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Sauve la valeurs<br />&nbsp; &nbsp; [defaults setInteger:scoremax forKey:raz];&nbsp; &nbsp; // des réglages<br />}<br />
    


    quelqu'un à  une idée de pourquoi ça ne marche pas ??
  • mpergandmpergand Membre
    19:36 modifié #9
    Le code a l'air correct.
    Les méthodes sont bien appelées ?

    Tu peux vérifier le contenu du fichier préférences avec PlistEditor.
  • prepa75prepa75 Membre
    19:36 modifié #10
    C'est bon ça marche  :D

    mais les méthodes - applicationDidFinishLaunching: et applicationWillTerminate: ne marchent pas...(ou du moins je n'arrive pas à  les utiliser  :P)

    du coup j'ai du mettre le code dans un IBAction
    <br /><br />-(IBAction)fenetre:(NSPopUpButton*)button<br />{<br />	<br />	defaults = [NSUserDefaults standardUserDefaults] ;&nbsp; &nbsp; &nbsp; &nbsp; <br />&nbsp; &nbsp; scoremax = [defaults integerForKey:raz] ;<br />&nbsp; &nbsp; [best setIntValue:scoremax] ;<br />	printf(&quot;&#092;n&#092;nfinalisation chargement&#092;n&#092;n&quot;);<br />	<br />	[defaults setInteger:scoremax forKey:raz];&nbsp; <br />	printf(&quot;&#092;n&#092;nfinalisation extinction&#092;n&#092;n&quot;);<br />
    


    quelqu'un a une idée pourquoi mon code du message précédent ne marche pas ?


  • prepa75prepa75 Membre
    19:36 modifié #11
    dans 1270141710:

    Le code a l'air correct.
    Les méthodes sont bien appelées ?

    Tu peux vérifier le contenu du fichier préférences avec PlistEditor.


    les méthodes sont en effet bien appelées , tu peut me détailler en quelques lignes l'utilisation de PlistEditor s'il te plait ?  :P
  • AliGatorAliGator Membre, Modérateur
    19:36 modifié #12
    Tu as bien mis ledit code dans la classe qui te sert de delegate de ton UIApplication bien sûr ?
  • mpergandmpergand Membre
    19:36 modifié #13
    Il faut que ta classe soit delegate de NSApplication.
    Ca se fixe dans IB, il faut tirer un lien entre NSApplication et ta classe et choisir delegate.
  • mpergandmpergand Membre
    19:36 modifié #14
    dans 1270142109:

    tu peut me détailler en quelques lignes l'utilisation de PlistEditor s'il te plait ?  :P


    Dans le dossier Preferences, tu fais un double-clic sur ton fichier  :P
  • prepa75prepa75 Membre
    19:36 modifié #15
    dans 1270142124:

    Tu as bien mis ledit code dans la classe qui te sert de delegate de ton UIApplication bien sûr ?


    Bien sur que OUI...non  :D

    merci Ali et mpergand ça marche nikel...
  • prepa75prepa75 Membre
    19:36 modifié #16
    D'après les commentaires de mon ami qui a testé mon application : il a put modifier les préférences dans la racine de l'application et ainsi modifier le score  :P

    comment pourrais-je faire pour enrayer ce problème ? B)
  • mpergandmpergand Membre
    avril 2010 modifié #17
    Les préférences ne se trouvent pas à  la racine de l'appli  B)

    Pour masquer le score, on va le transformer en data:
    <br />NSData* data=[NSArchiver archivedDataWithRootObject:[NSNumber numberWithInt:scoremax]];<br />[defaults setObject:data forKey:raz];<br /><br />// et pour le récupérer<br />NSData* data=[defaults objectForKey:raz];<br />NSNumber* num=[NSUnarchiver unarchiveObjectWithData:data];<br /><br />scoremax=[num intValue];<br />
    
  • AliGatorAliGator Membre, Modérateur
    avril 2010 modifié #18
    Au passage, ça aurait été le même problème en écrivant dans un fichier avec ton NSArray et writeToFile ;)
    • Le mieux c'est d'encrypter ton score de façon un peu plus "bâtarde" pour que ce soit moins compréhensible.
      Genre encapsuler ça dans un NSData (qui fait partie des types que tu peux stocker dans les NSDefaults, mais qui sont bien moins intelligibles à  lire qu'un simple entier). " [EDIT] Bon grillé par mpergand sur le coup, et c'est vrai qu'utiliser NSArchiver pour ça c'est plus sympa d'ailleurs au passage que ce que j'ai mis dans mon exemple plus bas[/EDIT]
    • Au lieu de mettre directement le score dans le NSData, tu peux faire un petit calcul à  la noix pour que ça soit un peu moins clair à  trouver dans les prefs.
    • Et même tu peux faire deux petits calculs à  la noix (différents bien sûr) plutôt qu'un, les stocker tous les deux dans le fichier. Ou sur le même principe, calculer un checksum (après tout, ça revient au même). Et vérifier qu'il est toujours correct à  la lecture du fichier.

    Comme ça si un petit malin essaye de modifier l'une ou l'autre des valeurs, comme bien sûr tu garderas secret la formule de ton petit calcul, il ne saura pas quelle valeur mettre, et s'il met un truc au hasard pour essayer de bidouiller le fichier, tu le détecteras tout de suite.



    Exemple :
    int scoremax = ...<br /><br />// calcul à  la noix (inversible) pour générer un nombre qui ne soit pas directement le score<br />unsigned long scoreToStore = (17+scoremax*53) ^ 0xD6C3; // (rappel : &quot;^&quot; est l&#39;opérateur XOR bit à  bit)<br />// calcul à  la noix n°2 (pas besoin d&#39;être réversible, sert de checksum)<br />unsigned long checkSum = pow(scoremax*213 , 3) % 0xFC23;&nbsp; // par exemple<br /><br />// encapsuler les deux dans un NSData pour brouiller encore plus les pistes<br />NSMutableData* d = [NSMutableData dataWithBytes:&amp;scoreToStore length:sizeof(unsigned long)];<br />[d appendBytes:&amp;checksum length:sizeof(unsigned long)];<br /><br />[[NSUserDefaults standardUserDefaults] setObject:d forKey:@&quot;raz&quot;];
    


    Et pour relire :
    unsigned int storedScore = 0;<br />unsigned int storedCheckSum = 0;<br /><br />// Extraire les unsigned long du NSData<br />NSData* d = [[NSUserDefaults standardUserDefaults] objectForKey:@&quot;raz&quot;];<br />[d getBytes:&amp;storedScore range:NSMakeRange(0, sizeof(unsigned long))];<br />[d getBytes:&amp;storedCheckSum range:NSMakeRange(sizeof(unsigned long), sizeof(unsigned long))];<br /><br />// faire le calcul inverse au calcul à  la noix (rappel : (A xor N) xor N = A)<br />unsigned long scoremax = (storedScore^0xD6C3 - 17)/53;<br />// recalculer le checksum<br />unsigned long checksum = pow(scoremax*213 , 3) % 0xFC23; <br />if (checksum != storedCheckSum) {<br />&nbsp; // hé ho, y&#39;a un petit malin qui a essayé de tricher, le checksum ne colle pas !<br />} else {<br />&nbsp; // c&#39;est bon, le fichier de prefs semble être authetique, tu peux utiliser scoremax<br />}
    
    Bon évidemment ce ne sont que des exemples, mais tu vois l'idée.

    En plus dans mon exemple comme tu peux le voir je met les deux nombres dans le même NSData (l'un à  la suite de l'autre, le premier unsigned long dans les 4 premiers octets du NSData, le 2e dans les 4 octets suivants), ce qui brouille encore plus les pistes, le tricheur risquant encore moins de comprendre que cette valeur dans les prefs est en fait une concaténation de deux valeurs...
  • prepa75prepa75 Membre
    19:36 modifié #19
    Merci beaucoup, vous avez parfaitement répondu à  ma question 

    héhé jvais lui mettre un ptit message fort sympathique s'il bidouille les scores  :P

    Bonne soirée  ;)
Connectez-vous ou Inscrivez-vous pour répondre.