Vues avec n°d'identification [résolu]

MAGEMAGE Membre
juin 2010 modifié dans API UIKit #1
Avant de me lancer dans un projet j'aimerai avoir vos avis d'expert sur la manière générale d'appréhender le tout.

Le projet consiste à  avoir un certain nombre de fiches (avec une image en recto et un texte en verso). A partir d'une vue, on charge quatre de ces fiches (au hasard). Depuis là , on clique sur une des fiches pour en avoir le détail :

J'aimerai éviter de créer trop de vues inutiles. J'avais donc l'intention de créer des nib pour chaque fiche (avec recto/verso inclus). Ensuite, je pensais leur donner un n° d'identification et utiliser ce numéro pour les afficher et les tirer au hasard.

Est-ce que je suis dans le juste ? et est-ce que je peux afficher plusieurs de ces fiches (donc des vues) dans une autre ?

Je n'ai pas encore bien déterminé la méthode, mais je pense à  long terme traduire les textes sur les fiches. Ces textes devraient-ils aussi être pris en compte dans la conception de départ ou puis-je m'en occuper plus tard ?

Je suis encore très au début, mais j'ai vu qu'en partant de ce qui existe (tutos - merci philippe - , exemple apple et autre) je partais pas dans la bonne direction. Heureusement, cela - et toujours grâce à  ce formidable forum - m'a permis d'apprendre et ce n'est jamais perdu.

Réponses

  • AliGatorAliGator Membre, Modérateur
    12:39 modifié #2
    Un fichier XIB pour rappel n'est rien d'autre finalement qu'une "archive d'objets, interconnectés entre eux".

    Lorsque tu crées un XIB, tu positionnes tes objects (en général objets graphiques genre UIView, UIButton...) dans InterfaceBuilder, tu les connectes entre eux, puis tu sauves le XIB.
    Dans ton code, à  un moment donné (explicitement ou implicitement) tu vas demander le "désarchivage" du XIB. Cela aura pour effet d'aller "lire le contenu du XIB" et reconstruire ces objets, les positionner au bon endroit, et les interconnecter entre eux, le tout en une ligne de code.

    Un peu comme si tu te préparais une arborescence de fichiers dans le Finder, une fois qu'elle était prête, tu la zippais... et quand tu avais besoin de recréer cette arborescence, t'avais plus qu'à  désarchiver ton ZIP à  l'endroit voulu, puis éventuellement rajouter 2 ou 3 fichiers à  cette arborescence déjà  préparée.

    Donc si ta UIView représentant une fiche (appellons là  UIFicheView, sous-classe perso de UIView) a une interface constituée de quelques titres statiques et d'un texte qui lui par contre est différent d'une fiche à  l'autre, un XIB est tout à  fait adapté. Mais attention à  respecter le modèle MVC, je n'ai pas l'impression que tu aies la bonne vision (en particulier quand tu parles de tes craintes lors de la traduction)...

    L'idée est donc de créer un XIB représentant l'interface (générique) que tu vas utiliser pour une fiche... on est bien d'accord, il n'y aura qu'un seul XIB, utilisé comme modèle pour toutes les instances de fiches que tu vas créer, même si tu as 30 fiches avec des contenus différents, chaque fiche aura une présentation commune, seul le texte de chaque fiche sera différent.

    Donc dans ton "UIFicheView.xib", tu crées une UIView, y place quelques UILabels pour les textes génériques genre labels statiques "Titre :", "Contenu :", "Description", et des UILabels ou UITextView (selon ce que tu veux afficher et si tu veux du texte éditable etc) pour recevoir les contenus de tes fiches... mais tu laisses ces contenus vides, on modifiera ces contenus par code pour chaque ficher créée puisque chaque fiche aura un contenu différent !
    Il suffit donc de prévoir un IBOutlet vers ces zones de texte (UILabels ou UITextView) qui afficheront le contenu de ta fiche, et on pourra alors remplir leur contenu par code.


    Après, le reste c'est côté modèle que ça se passe : tu peux avoir un tableau de contenus, et quand tu veux créer 4 fiches au hasard, tu crées 4 UIFicheView chacune à  partir de ton XIB "UIFicheView.xib", ce qui va te créer des interfaces de fiches toutes préparées... et il te suffira de les remplir. Après le côté "je choisis 4 fiches au hasard" c'est dans la partie modèle, dans ton tableau de contenus, que tu vas aller récupérer 4 textes au hasard, et remplir chacune de tes 4 UIFicheView par un de ces 4 texte, pour qu'ainsi chacune de tes 4 UIFicheView, basées sur le même modèle d'interface (ton XIB), ait un contenu différent.

    Ne va en tout cas surtout pas créer un fichier XIB par fiche que tu veux créer dans ton app !! Tu ne t'en sortirais pas !!
  • MAGEMAGE Membre
    12:39 modifié #3
    Limpide ! Je comprends mieux le paradigme, merci.

    Donc je vais travailler la création de tableaux... et je reviendrai certainement vous embêter.
  • MAGEMAGE Membre
    12:39 modifié #4
    Bon, sur les tableaux je suis vraiment pas doué. Après une semaine dessus, je n'y suis pas arrivé. J'ai bien essayé d'utiliser un NSDictionery ou des NSArray, mais non. J'ai tenté de suivre des tutos, mais là  aussi on part chaque fois d'une TableView alors que j'aimerai intégrer les données dans un XIB avec des champs (label, texte et image).

    Bon, même si c'est plus long, j'ai pu m'en sortir avec du MVC sans tableau. J'ai intégré sans souci mes donnée dans un XIB comme ceci :
    <br />switch (random()%22) {<br />		case 0:<br />			titre.text = @&quot;Titre 0&quot;<br />			titreTexte.text = titre.text;<br />			texte.text = @&quot;blablabla...&quot;;<br />			image.image= [UIImage imageNamed:@&quot;image0.png&quot;];<br />			break;<br />		case 1: ...<br />
    


    Le problème qui reste est que je fais 4 tirage et que je voudrai enlever le cas déjà  tiré. Par exemple, si a fiche 5 sort au premier choix, qu'elle ne puisse plus sortir au deuxième.
  • AliGatorAliGator Membre, Modérateur
    avril 2009 modifié #5
    Bah je te répondrais bien .... de faire un tableau  :P :) et d'enlever de ce tableau la valeur tirée à  chaque tirage pour être sûr de pas repiocher dedans  ;)

    Peux-tu nous dire exactement ce qui t'embête avec les tableaux, ce que tu n'arrives pas à  cerner ?

    Un tableau en Cocoa peut contenir n'importe quel type de données (n'importe quel type d'objet plus exactement). A noter aussi que quand tu mets un objet dans un NSArray, cet objet est retenu par le tableau (le tableau envoie un retain implicite à  l'objet) et quand tu enlèves cet objet du tableau (ou quand le tableau est "releasé"), le tableau envoie un release implicite au tableau. Enfin, les NSArray sont des tableaux constants c'est à  dire qu'on ne peux pas leur ajouter ou supprimer des éléments, alors que les NSMutableArray on peut modifier leur contenu même après leur création.

    Après, il suffit de les utiliser comme toute autre classe Cocoa :
    // 1) Création du tableau et remplissage initial<br />NSMutableArray* tableauTitres = [[NSMutableArray alloc] init];<br />[tableauTitres addObject:@&quot;Titre 0&quot;];<br />[tableauTitres addObject:@&quot;Titre 1&quot;];<br />[tableauTitres addObject:@&quot;Titre 2&quot;];<br />...<br />// --&gt; ici on a un tableau de NSString, si on veut la NSString d&#39;index 3, il suffira<br />//&nbsp; &nbsp; &nbsp; de demander [tableauTitres objectAtIndex:3] pour le récupérer.<br /><br />// 2) Faire 4 tirages aléatoires, *sans remise*<br />for(int i=0;i&lt;4;i++)<br />{<br />  idx = random()%[tableauTitres count]; // modulo le nombre de titres présents dans le tableau<br />  NSString* titre = [tableauTitres objectAtIndex:idx]; // récupérer l&#39;élément idx du tableau<br /><br />  titre.text = titre;<br />  titreTexte.text = titre;<br /><br />  // et retirer le titre &quot;pioché&quot; du tableau pour éviter de le repiocher au tirage suivant (sans remise)<br />  [tableauTitres removeObjectAtIndex:idx];<br />} // hop, tirage suivant... qui ne va plus piocher que sur les titres restants<br /><br />// 3) Libérer la mémoire une fois qu&#39;on en a fini en relâchant le tableau<br />[tableauTitres release];
    
    Voilà  pour le principe de base.

    Après, si tu fais ce tirage à  plusieurs moments dans ton appli (et pas juste une seule fois à  l'initialisation), ça peut être plus propre de créer ton tableau de titres au tout début (dans le "init" de ta classe typiquement, et tu fais le release de ce tableau dans le "dealloc"), et au moment du tirage, de demander une copie (mutableCopy) de ce tableau (pour pouvoir faire les tirages en enlevant les éléments piochés de cette copie au fur et à  mesure, sans alterer le tableau complet original), faire les tirages, et relâcher cette copie altérée à  la fin des tirages.
    Comme ça tu gardes à  tout moment ton tableau de titres complet avec tous les titres dedans, et ne travaille que sur une copie que tu modifies pour faire tes tirages, sans altérer le tableau complet dont tu auras besoin si tu veux faire un nouveau tirage sur l'ensemble des fiches.



    Voilà , déjà  je te laisse faire des tests en utilisant juste le titre de tes fiches (et laissant de côté "texte" et "image" pour l'instant), pour voir si tu arrives à  faire fonctionner le code que je t'ai livré et si tu as des questions. On rajoutera la gestion de "texte" et "image" ensuite une fois la première partie maà®trisée.
  • MAGEMAGE Membre
    12:39 modifié #6
    Premier soucis avec la variable idx ! Il ne me l'accepte pas: "undeclared". Après déclaration dans le .h : il me dit "assignment makes pointer from integer without a cast".
  • AliGatorAliGator Membre, Modérateur
    12:39 modifié #7
    Oui bah j'ai tapé le pseudo code comme ça vite fait dans le forum, en effet j'ai oublié de déclarer idx... mais il va de soi qu'elle est à  déclarer au début de la boucle for, en tant que int (voire en tant que NSUInteger). (Pas besoin d'en faire une variable d'instance de ta classe, oulà  ! Une déclaration locale à  ta fonction suffit amplement !!)

    Ensuite vu le warning tu essayes d'affecter un integer à  une variable qui est de type pointeur. Tu n'aurais pas déclaré idx comme "int* idx" au lieu de "int idx" par hasard ?!
  • MAGEMAGE Membre
    12:39 modifié #8
    Bien vu... je fais encore des erreurs de débutants, désolé.

    J'ai maintenant une erreur au niveau du simulateur : Program received signal:  “EXC_ARITHMETIC”. et semble bloquer sur la fonction random ?
  • AliGatorAliGator Membre, Modérateur
    12:39 modifié #9
    Bah heu... je vais pas te mener par la main étape par étape, tu peux pas creuser un peu ?
    Je sais pas moi, mettre des NSLog pour isoler le moment où il crash (et voir via ces NSLogs si les valeurs que tu obtiens aux étapes intermédiaires sont cohérentes aussi), remplacer random() par une valeur fixe quelconque (le temps des tests) pour voir si c'est bien random qui pose problème ou pas, mettre des breakpoints... tout ça quoi.
  • MAGEMAGE Membre
    avril 2009 modifié #10
    Oui, j'abuse, pardon. Je vais chercher. Merci pour toutes ces pistes.

    [edit] : Tout est rentré dans l'ordre. J'ai même réussi à  faire un tableau avec des images. Une petite dernière question pour la route si j'ose : Comment faire pour lier tous ces éléments. C'est à  dire que lorsque je tire le titre 5, l'image apparaisse ?
  • MAGEMAGE Membre
    avril 2009 modifié #11
    Bon, je donne quand même quelques nouvelles pour remercier une fois encore AlliGator pour son coup de pouce et sans qui je n'aurai pu continuer.  :kicking:
    <br />// titres<br />NSMutableArray* tableauTitres = [[NSMutableArray alloc] init];<br />[tableauTitres insertObject:NSLocalizedString (@&quot;titre0&quot;, @&quot;fiche 0&quot;) atIndex:0];[<br />...<br />NSMutableArray* tableauImages = [[NSMutableArray alloc] init];<br />[tableauImages insertObject:[UIImage imageNamed:@&quot;00.png&quot;] atIndex:0];<br />...<br />NSMutableArray* tableauTextePour = [[NSMutableArray alloc] init];<br />[tableauTextePour insertObject: NSLocalizedString (@&quot;pour0&quot;, @&quot;fiche 0&quot;)atIndex:0];<br />...<br />NSMutableArray* tableauTexteContre = [[NSMutableArray alloc] init];<br />[tableauTexteContre insertObject: NSLocalizedString (@&quot;contre0&quot;, @&quot;fiche 0&quot;)atIndex:0];<br />...<br />...<br />	for(int i=0;i&lt;4;i++)<br />	{<br />		int idx;<br />		idx = random()%[tableauTitres count];<br />		<br />		UIImage* face = [tableauImages objectAtIndex:idx];<br />		imageActuel.image = face;	<br />						<br />		NSString* titre = [tableauTitres objectAtIndex:idx];<br />		titreActuelImage.text = titre;<br />		titreActuelTexte.text = titre;<br />			<br />		NSString* textePour = [tableauTextePour objectAtIndex:idx];<br />		texteActuel.text = textePour;<br />			<br />		NSString* texteContre = [tableauTexteContre objectAtIndex:idx];<br />		//texteNegatif.text = texteContre;<br />			<br />		[tableauImages removeObjectAtIndex:idx];<br />		[tableauTitres removeObjectAtIndex:idx];<br />		[tableauTextePour removeObjectAtIndex:idx];<br />		[tableauTexteContre removeObjectAtIndex:idx];<br />			<br />	}<br />...<br />
    


    Pas mal, pour un débutant hein ?... enfin je pense que j'ai tout bon, parce que ça me semble bien fonctionner. J'ai ajouté les numéros d'index pour que tous mes éléments soit classés dans le même ordre et réutiliser le idx pour tirer les différents éléments au même index.

    Je me demandai encore quelque chose à  ce propos. Disons que dans mon cas j'affiche parfois le textePour et parfois le texteContre sur ma fiche. Dans le code je tire tout de même les deux textes pour les supprimer ; mais comme ils sont indexés d'une manière fixe, ça devrait marcher aussi si je ne le tire pas je pense.
  • Philippe49Philippe49 Membre
    12:39 modifié #12
    dans 1240496565:

    Pas mal, pour un débutant hein ?... 

    Yes !!


    A priori ta boucle for(int i=0;i<4;i++) va planter : au deuxième passage (i=1) , il n'y a plus rien dans tableauTitres, le idx est donc random()%0 ! mais bon si tu as prévu de mettre 4 objets dans chacun des NSArray, cela devrait rouler.

    Plutôt que des mettre du code un peu peu long les 4*4 insertObject: atIndex: peuvent être remplacés par
    <br />	NSMutableArray * tableauTitres=[[NSArray alloc] initWithObjects:<br />		NSLocalizedString (@&quot;titre0&quot;, @&quot;fiche 0&quot;),<br />		NSLocalizedString (@&quot;titre1&quot;, @&quot;fiche 1&quot;),<br />		NSLocalizedString (@&quot;titre2&quot;, @&quot;fiche 2&quot;),<br />		NSLocalizedString (@&quot;titre3&quot;, @&quot;fiche 3&quot;),<br />		nil<br />	];
    

  • AliGatorAliGator Membre, Modérateur
    12:39 modifié #13
    Oui, Philippe, je pense qu'il a mis les "..." dans son code pour nous mentionner l'insertion d'autres objets, il doit en avoir plus d'un dans ses tableaux bien sûr :D

    Pour le "initWithObjects:..." au lieu du "insertObject: atIndex:" je ne peux que "plussoyer" comme on dit, c'est en effet plus propre. Et sinon MAGE même si tu préfères créer ses éléments dans des lignes de code séparées, je te conseille d'utiliser la méthode "addObject" (qui va rajouter l'objet à  la fin du tableau) plutôt que "insertObject: atIndex:", d'une part parce que si Cocoa sait que tu veux insérer l'objet à  la fin, il va le faire plus rapidement que s'il a à  chercher l'index (bon ok côté gain de temps c'est vraiment plus que risible mais bon) mais surtout parce que c'est plus simple, tu n'as pas à  spécifier l'index, au risque d'oublier de l'incrémenter au gré d'un copier/coller de lignes...



    Bon ton code est propre et en effet ça doit faire ce que tu veux.
    Ceci dit je te propose dans les posts suivant d'aller plus loin, dans un but pédagogique mais aussi pour te faire aux bonnes pratique courantes en Cocoa :

    (1) Prochaine étape : regrouper tes données dans un NSArray de NSDictionary plutôt que d'avoir tout plein de NSArrays

    (2) Etape suivante ensuite : définir tes données (donc ton NSArray de NSDictionary) dans un fichier plist, et non pas en dur dans le code, ce qui d'une t'évitera un gros paquet de lignes de code juste pour remplir tes tableaux, et permettra en plus de séparer le code (la logique de fonctionnement) des données dans un fichier séparé (et plus simple pour la traduction à  terme) !
  • AliGatorAliGator Membre, Modérateur
    avril 2009 modifié #14
    Alors on commence...
    Evolution n°1 : Utiliser un NSArray de NSDictionary

    L'idée c'est qu'au lieu d'avoir N tableaux (tableauTitres, tableauImages, tableauTextePour, tableauTexteContre, ...), tu n'en aies qu'un seul, qui au lieu de contenir une chaà®ne, va contenir un NSDictionary. Et chaque NSDictionnary sera constitué de N clés, qui seront "titre", "image", "textePour", "texteContre", et donc la valeur associée sera bah le contenu correspondant.

    Ainsi, au lieu d'avoir :
    titre.text = [tableauTitres objectAtIndex: idx];<br />image.image = [UIImage imageNamed:[tableauImages objectAtIndex: idx]];<br />textePour.text = [tableauTextePour objectAtIndex: idx];<br />texteContre.text = [tableauTexteContre objectAtIndex: idx];<br />...
    
    Tu auras :
    NSDictionary* infosFiche = [tableauFiches objectAtIndex: idx];<br /><br />titre.text = [infosFiche objectForKey:@&quot;titre&quot;];<br />image.image = [UIImage imageNamed: [infosFiche objectForKey:@&quot;imageName&quot;]];<br />textePour.text = [infosFiche objectForKey:@&quot;textePour&quot;];<br />texteContre.text = [infosFiche objectForKey:@&quot;texteContre&quot;];<br />...
    



    Voilà  pour l'idée, je te laisse coder ça si cette solution te séduit.
    Ce n'est qu'une alternative possible et pas obligatoire hein (car ta solution à  toi marche très bien aussi), mais cette solution a l'avantage d'éviter de démultiplier les tableaux (et d'avoir du coup 36 variables d'instance), et d'être sûr de la consistance (alors qu'avec plusieurs tableaux si jamais tu ajoutes une entrée dans un des tableaux et que tu oublies d'ajouter les infos correspondantes dans l'autre, ça va tout te décaler... et faut être sûr que les éléments correspondants soient aux mêmes indices pour que ça marche... avec un NSArray de NSDicos t'as pas ce pb)...

    ... Et puis si tu adoptes ce modèle plutôt que plein de NSArrays, ça facilitera le passage à  l'évolution n°2 :)
  • MAGEMAGE Membre
    12:39 modifié #15
    Oui Philippe, les "...", c'était pour prendre moins de place et Oui AliGator, je veux bien apprendre  ::)

    Je comprends bien l'idée de mettre tout dans un dictionary et d'en sortir les éléments par ligne, mais c'est justement parce que je n'arrive pas à  tirer un code de la doc que j'avais laissé tomber les tableaux.

    Je vais encore me faire taper sur les doigts, mais est-ce que je suis dans le juste avec ça pour créer mon dico ?
    <br />+ (id)dictionaryWithObject:(id)fiche forKey:(id)theKeys{	<br />NSArray *tableauFiche = [NSArray arrayWithObjects:@&quot;titre&quot;, @&quot;imageName&quot;, @&quot;textePour&quot;, @&quot;texteContre&quot;,nil];<br />NSArray *fiche0 = [NSArray arrayWithObjects:@&quot;titre0&quot;, @&quot;00.png&quot;, NSLocalizedString (@&quot;pour0&quot;, @&quot;Carte 0&quot;), NSLocalizedString (@&quot;contre0&quot;, @&quot;Carte 0&quot;), nil];<br />NSArray *fiche1 = [NSArray arrayWithObjects:@&quot;titre1&quot;, @&quot;01.png&quot;, NSLocalizedString (@&quot;pour1&quot;, @&quot;Carte 1&quot;), NSLocalizedString (@&quot;contre1&quot;, @&quot;Carte 1&quot;), nil];<br />...<br />}<br />
    


    ps: le code avec "initWithObjects..." plantouille complètement. Je vais travailler l'histoire et je vous redonnerai des nouvelles  ;)
  • AliGatorAliGator Membre, Modérateur
    avril 2009 modifié #16
    Heu pourquoi tu surcharges la méthode "dictionaryWithObject:forKey:" de la classe NSDictionary là  ?

    Le but est de créer un dictionnaire pour chaque fiche... donc d'appeller une des méthodes dictionaryWith... par exemple que propose NSDictionary, pour créer ce dictionnaire. Comme tu appelles "arrayWithObjects:" pour créer ton tableau. En tout cas pas en surchargeant (redéfinissant le code de) la méthode dictionaryWithObject:forKey: !

    Sinon pour le reste du code (celui que tu as mis à  l'intérieur des accolades quoi), faut bien que tu aies la vision que chaque fiche va être représentée par un NSDictionary. Par exemple la fiche 0 correspondra à  un dictionnaire de ce genre :
    {
      titre = @titre0,
      imageName = @00.png,
      textePour = @pour0,
      texteContre = @contre0
    }
    . Après, tu peux créer un NSArray (tableau) contenant toutes tes fiches comme objet (chaque case du tableau est une fiche, représentée par un NSDictionary tel que décrit plus haut)

    Donc le code ça serait plutôt du genre, au début pour créer chacune de tes fiches :
    NSArray *keys = [NSArray arrayWithObjects:@&quot;titre&quot;, @&quot;imageName&quot;, @&quot;textePour&quot;, @&quot;texteContre&quot;,nil];<br /><br />NSArray *fiche0 = [NSArray arrayWithObjects:@&quot;titre0&quot;, @&quot;00.png&quot;, NSLocalizedString (@&quot;pour0&quot;, @&quot;Carte 0&quot;), NSLocalizedString (@&quot;contre0&quot;, @&quot;Carte 0&quot;), nil];<br />NSDictionary* fiche0 = [NSDictionary dictionaryWithObjects:fiche0data forKeys:keys];<br /><br />NSArray *fiche1data = [NSArray arrayWithObjects:@&quot;titre1&quot;, @&quot;01.png&quot;, NSLocalizedString (@&quot;pour1&quot;, @&quot;Carte 1&quot;), NSLocalizedString (@&quot;contre1&quot;, @&quot;Carte 1&quot;), nil];<br />NSDictionary* fiche1 = [NSDictionary dictionaryWithObjects:fiche1data forKeys:keys];<br /><br />...
    
    Ou une autre façon de faire tout aussi valable :
    NSDictionary* fiche0 = [NSDictionary dictionaryWithObjectsAndKeys:  @&quot;titre0&quot;,@&quot;titre&quot; , @&quot;00.png&quot;,@&quot;imageName&quot; , @&quot;pour0&quot;,@&quot;textePour&quot; , @&quot;contre0&quot;,@&quot;texteContre&quot; , nil];<br />NSDictionary* fiche1 = [NSDictionary dictionaryWithObjectsAndKeys:  @&quot;titre1&quot;,@&quot;titre&quot; , @&quot;01.png&quot;,@&quot;imageName&quot; , @&quot;pour1&quot;,@&quot;textePour&quot; , @&quot;contre1&quot;,@&quot;texteContre&quot; , nil];<br />...
    
    A la fin de ce genre de code (que soit la variante choisie (parmi ces 2 là  ou d'autres ayant le même résultat), tu as un NSDictionary par fiche... qu'il ne suffit plus que de regrouper dans un tableau :
    NSArray* mesFiches = [NSArray arrayWithObjects: fiche0, fiche1, ..., nil];<br />// penser à  faire un retain sur mesFiches (ou à  appeller &quot;alloc&quot;+&quot;initWithObjects:&quot; à  la place de &quot;arrayWithObjects&quot; si tu la passes en ivar et plus en variable locale<br />
    
    Et à  la fin de tout ça, si tu veux récupérer toutes les infos de la fiche n°3, tu fais [tt]NSDictionary* maFiche3 = [mesFiches objectAtIndex:3];[/tt]. Et si tu fais un NSLog de ce résultat, tu retrouves le dictionary dont je t'ai donné la tronche plus haut... Après une fois que tu lui a demandé la fiche voulue et récupéré ce résultat, tu peux demander ce que tu veux à  propos de la fiche (quand son titre, quand son imageName, ...) en interrogeant le NSDictionary récupéré et la décrivant, avec [tt]objectForKey:@titre[/tt] ou du genre.
  • MAGEMAGE Membre
    12:39 modifié #17
    Voilà , j'y suis. Tout fonctionne. ;)

    Je me pose juste la question de l'utilité de:
    for(int i=0;i&lt;19;i++)
    

    Car la fonction de tirage vient de
    idx = random()%[tableauFiches count];
    

    ça fonctionne d'ailleurs sans.

    [tt]Remarque: j'ai mis i<19, car j'ai 22 fiches. Je pensais qu'il fallait mettre i<20, mais ça plantait.[/tt]
  • Philippe49Philippe49 Membre
    12:39 modifié #18
    dans 1240661516:

    Je me pose juste la question de l'utilité de:
    [tt]Remarque: j'ai mis i<19, car j'ai 22 fiches. Je pensais qu'il fallait mettre i<20, mais ça plantait.[/tt]


    A priori avec 22 fiches tirées une par une il faut mettre ni i<19 ni i<20 mais i<22  ?
  • MAGEMAGE Membre
    12:39 modifié #19
    Je pensais à  21 en fait, car je comptais le 0.

    J'ai compris où ça plante. Puisque j'enlève une ligne à  chaque tirage, j'ai bien 22 au premier, mais 21 au deuxième, 20 au troisième et 19 au quatrième... et comme je tire quatre fois.
  • AliGatorAliGator Membre, Modérateur
    avril 2009 modifié #20
    Oui mais je vois pas d'où vient ton 19... en dur.
    Enfin où tu as cette boucle "for" en fait...
    • tu fais 4 tirages, donc tu boucles 4 fois, et donc dans le for tu vas jusqu'à  4 "for(i=0;i<4;i++)"
    • là  où tu as besoin du nombre de fiches c'est au moment de chaque tirage (donc dans chacune des 4 itérations de ta boucle for), où là  il faut que tu tires un nombre entre 0 et.. le nombre de fiches parmi lesquelles tu vas trier (enfin ce nombre -1, puisque tu pars de zéro).
      Mais ça c'est quand tu fais ton random(), et dans ce cas il faut utiliser [tableauFiches count] et pas mettre un nombre comme 19 ou 22 en dur.
      Comme ça déjà  c'est plus logique/lisible*, en plus quand au fur et à  mesure des tirages le compte change, ça correspond toujours, et en plus si un jour tu rajoutes des fiches dans ton tableau tout se fera toujours tout seul tu n'auras rien à  changer


    *En informatique on parle parfois de "magic number", pour indiquer dans du code des nombre qui sont là  dans le code "comme par magie" mais on se demande d'où ils viennent, plus exactement si on lit le programme d'un autre, quand on tombe sur un nombre dont on ne sais pas d'où il sort et qu'on capte pas pourquoi l'auteur du code a mis cette valeur.
    Il faut mieux dans ce cas à  la limite utiliser des constantes, ou un appel explicite à  une fonction (c'est le cas pour toi d'autant que cette valeur de count change), ou laisser le calcul décomposé de la valeur, genre 22-4+1 (ou mieux kNombreFiches-kNombreTirages+1) plutôt que de mettre un 19 dont on ne sait d'où il sort...


    En tout cas dans ton cas je vois pas ce que tu fais avec le "19" dans ton "for"... ou alors on parle pas du même "for" (pas la boucle qui répète un tirage autant de fois... que tu veux faire de tirages, mais une autre boucle for) mais dans ce cas explique nous de laquelle tu parles :P Et sinon si c'est pour ton random faut garder [tableau count] vu justement qu'il change !
  • MAGEMAGE Membre
    12:39 modifié #21
    On parle bien du même for. C'était bien 4 qu'il fallait laisser.
    A force de modifications, j'ai perdu quelques concepts en route.

    Très intéressante l'explication du "magic number".
  • MAGEMAGE Membre
    12:39 modifié #22
    Ali, je suis prêt pour l'évolution n°2... si tu veux bien ?

    (2) Etape suivante ensuite : définir tes données (donc ton NSArray de NSDictionary) dans un fichier plist, et non pas en dur dans le code, ce qui d'une t'évitera un gros paquet de lignes de code juste pour remplir tes tableaux, et permettra en plus de séparer le code (la logique de fonctionnement) des données dans un fichier séparé (et plus simple pour la traduction à  terme) !


    Parce que c'est vrai que c'est pas super de devoir se balader dans le code ;)
  • AliGatorAliGator Membre, Modérateur
    12:39 modifié #23
    Pour l'étape 2, c'est pas compliqué : plutôt que d'avoir plein de lignes qui vont te créer tes fiches intermédiaires, puis ensuite toutes les regrouper dans un NSArray, pour finir avec un [tt]NSArray* fiches[/tt] (tableau contenant donc des NSDictionary représentant chacun une fiche), tu vas créer ton tableau dans un fichier "Fiches.plist", puis ensuite il suffira de le lire avec :
    NSArray* fiches = [NSArray arrayWithContentsOfFile:[NSBundle pathForResource:@&quot;Fiches&quot; ofType:@&quot;plist&quot;]];
    


    Pour créer le fichier Plist en question, rien de plus simple :
    • Dans Xcode choisir "New File..." puis aller dans la catégorie "Other" (tout en bas), et choisir le type de fichier "Property List" dans la partie droite. Cela va te créer un fichier plist vide et te l'afficher à  l'aide de l'éditeur de plist intégré à  Xcode (qui est en fait le même que l'utilitaire "Property List Editor" fourni avec les Dev Tools).
    • Tu définis le type de ta "racine" (l'élément "Root" que tu vois s'afficher) comme étant un NSArray (car c'est un NSArray de NSDictionary que l'on va créer, donc), à  l'aide du menu déroulant de la colonne "type", puis tu cliques sur le bouton tout à  droite au bout de la ligne pour rajouter une entrée.
    • Par défaut cette entrée sera de type String, tu modifies de même pour choisir cette fois Dictionary (on va ainsi créer la première fiche, de type NSDictionary). Puis tu ouvres le petit triangle à  gauche de "Item 1" pour dire "je vais ajouter des éléments DANS le dictionary" et tu cliques sur le bouton en bout de ligne pour rajouter une entrée dans le Dictionary.
    • Tu laisses cette entrée de type String, et le nom de la clé ça va être ta première clé, donc "title", sa valeur le titre de ta première fiche.
      Rajoute 3 autres entrées, pour "imageName", "textePour" et "texteContre" de la même manière.
    • Tu continues ainsi d'ajouter d'autres NSDictionary du même genre à  ton NSArray, pour rajouter les autres fiches.
      Astuce : une fois la première fiche (premier NSDictionary) préparé, tu peux sélectionner la ligne du NSDictionary et, après avoir refermé le petit triangle, faire un copier/coller pour le dubpliquer. Comme ça tu n'aurais que les valeurs à  changer pour les adapter aux autres fiches, mais les clés seront déjà  remplies.


    Et voilà . Tu t'assures que ton fichier plist est bien rajouté dans le dossier/groupe "Resources" à  gauche de ta fenêtre Xcode, et ça devrait être bon. Le simple [tt]arrayWithContentsOfFile[/tt] va lire le contenu du plist et recréer toute la structure pour toi en une ligne.
    Comme ça tu as toutes tes données regroupées dans le plist déjà , donc plus propre, et en plus ça sera plus simple ensuite pour traduire en plusieurs langues si nécessaire.
  • MAGEMAGE Membre
    12:39 modifié #24
    Merci Ali  ::)

    Tout me semblait très clair... mais je m'en sort pas tout à  fait  :o

    J'ai un warning :
    nsbundle may not respond to +pathForResource:ofType
    Après quelques recherches je pensais avoir trouvé le problème par une déclaration dans le .h mais ça n'a rien résolu.

    J'en profite pour vérifier deux idées :
    1) Est-ce une bonne méthode de passer mon tableau en mutable
    NSArray* fiches = [NSArray arrayWithContentsOfFile:[NSBundle pathForResource:@&quot;cartes&quot; ofType:@&quot;plist&quot;]];<br />NSMutableArray* tableauFiches = [[NSMutableArray alloc] initWithArray:fiches];
    

    ou c'est inutile et je peux directement le créer au départ ?

    2) pour ma localisation, j'avais :
    NSLocalizedString (@&quot;pour1&quot;, @&quot;Carte 1&quot;)
    

    qu'est-ce que je mets dans mon .plist ?
  • AliGatorAliGator Membre, Modérateur
    juin 2009 modifié #25
    Alors j'avoue que j'ai pondu le code sans regarder la doc ni sans le tester. Doc j'ai pas tapé la bonne méthode de la classe NSBundle pour lui demander d'aller chercher le chemin d'accès du plist.

    Il fallait donc utiliser la méthode d'instance "pathForResource:ofType:", à  appeler sur le mainBundle, et non la méthode de classe du même nom à  appeler sur la classe NSBundle elle-même (méthode... qui n'existe pas dans la doc de NSBundle en fait, y'a juste sa variante avec le paramètre "inDirectory", mais elle ne nous intéresse pas trop ici)

    Il fallait donc lire : [tt][[NSBundle mainBundle] pathForResource:@Fiches ofType:@plist][/tt].

    Sinon pour la localisation/traduction, c'est simple, tu ne vas plus créer une version de chaque chaà®ne contenue dans tes fiches pour chaque langue... mais carrément un fichier plist pour chaque langue.
    Ainsi tu auras un fichier plist pour les fiches en français, dont le contenu sera intégralement en français, une variante de ce plist pour la localisation anglaise, où tout sera en anglais dedans, etc.

    Pour cela, une fois que ton fichier "Fiches.plist" a été placé dans le groupe "Resources" (partie gauche "Groups & Files" dans la fenêtre Xcode) de ton projet, tu cliques sur le fichier plist, tu fais un Pomme-I dessus, et tu cliques sur le bouton "Make Localizable" (onglet "General). Cela va rendre ton plist traduisible, en t'associant de base la version actuelle du plist à  la langue anglaise (English). Après si tu retournes dans l'onglet "General" de ce panneau d'infos sur le plist, tu peux rajouter des traductions pour es langues différentes en cliquant sur "Add Localization". A gauche du fichier "Fiches.plist" que tu as dans ton groupe "Resources" tu auras de plus un petit triangle te permettant de voir les variantes de ton fichier plist, une pour chaque langue. Il te suffit de choisir une des variantes (par exemple celle pour French) et de modifier alors les valeurs que tu as mises dans ton plist pour toutes les passer en français.


    Sinon si tu veux pouvoir modifier tes fiches, tu peux créer un NSMutableArray directement normalement (faut s'assurer que tout soit "mutable" une fois chargé), et tu pourras ensuite si besoin réécrire sa version modifier sur le disque dans un (autre) plist. (Pas dans le plist d'origine car ce dernier est dans le "bundle" de ton appli donc non modifiable une fois l'appli compilée, mais il y a des répertoires adéquats pour ça si besoin, genre Application Support ou autre)
  • MAGEMAGE Membre
    12:39 modifié #26
    Alors j&#39;avoue que j&#39;ai pondu le code sans regarder...
    


    Alors j'avoue que j'avance grâce à  tes précieux conseils, Aligator  :p
  • MAGEMAGE Membre
    12:39 modifié #27
    J'ai fait les changements et tout à  l'air de bien fonctionner.

    J'ai dû par exemple enlever le
    [tableauFiches release];
    
    sinon ça plantait. J'ai pas vraiment compris pourquoi, sauf que j'ai vu que d'après cette méthode, il autorelease.

    Par contre, je ne sais pas si c'est la mise à  jour récente en 3.0 ou aux changements que je viens de faire, mais les actions sur ces tableaux sont bien plus lentes et moins fluides. Cela donne une impression de lourdeur.
  • 12:39 modifié #28
    dans 1245605942:

    J'ai fait les changements et tout à  l'air de bien fonctionner.

    J'ai dû par exemple enlever le
    [tableauFiches release];
    
    sinon ça plantait. J'ai pas vraiment compris pourquoi, sauf que j'ai vu que d'après cette méthode, il autorelease.

    Par contre, je ne sais pas si c'est la mise à  jour récente en 3.0 ou aux changements que je viens de faire, mais les actions sur ces tableaux sont bien plus lentes et moins fluides. Cela donne une impression de lourdeur.



    C'est un vrai poison cette v3... je suis vraiment déçu que ça soit la meme version que la GM distribuée aux développeurs... moi j'ai trouvé plein de bug sur la GM.. et surtout cette histoire de batterie qui se vide en 2 jours  >:(
Connectez-vous ou Inscrivez-vous pour répondre.