NSDictionary et NSMutableArray

2

Réponses

  • Philippe49Philippe49 Membre
    15:29 modifié #32
    L'appel est automatique, mais c'est le data source qui en fournit la réponse.
    Il faut donc implémenter cette méthode.
  • RocouRocou Membre
    15:29 modifié #33
    dans 1217000010:

    L'appel est automatique, mais c'est le data source qui en fournit la réponse.
    Il faut donc implémenter cette méthode.

    OK, mais je l'ai bien implémentée.
    Le problème ne vient donc pas de là .  :-\\
  • 15:29 modifié #34
    - (int)numberOfRowsInTableView:(NSTableView *)aTableView;

    En plaçant un point d'arrêt dans cette méthode, y-a-t-il une pause dans le programme ?
    En effet, cette méthode est la première invoquée. En fonction du résultat elle déclenche la méthode suivante pour chaque cellule (intersection entre colonne et ligne) de la table en question.
    S'il n'y a pas de pause, l'erreur vient de la connexion de la table avec sa source de données.

    - (id)tableView:(NSTableView *)aTableView
        objectValueForTableColumn:(NSTableColumn *)aTableColumn
        row:(int)rowIndex;

  • AliGatorAliGator Membre, Modérateur
    15:29 modifié #35
    dans 1217003472:

    OK, mais je l'ai bien implémentée.
    Le problème ne vient donc pas de là .  :-\\
    Ben en même temps quand tu dis que tu as écrit ce code :
    dans 1216992058:
    Dans ma boucle (celle qui ligne les lignes de mon fichier une par une), j'ai mis ce code:

    NSMutableDictionary * maligne=[NSMutableDictionary dictionaryWithObjectsAndKeys:valeur,@first,nil];
    model=[[NSArray alloc] initWithObjects:maligne,nil];

    tableView:objectValueForTableColumn:row:
    Ben ça donne l'impression (fausse ? ou pas ?) que tu as mis exactement "[tt]tableView:objectValueForTableColumn:row:[/tt]" comme ligne dans ton code, tel quel ?!
  • RocouRocou Membre
    15:29 modifié #36
    dans 1217007882:

    Ben en même temps quand tu dis que tu as écrit ce code :
    dans 1216992058:
    Dans ma boucle (celle qui ligne les lignes de mon fichier une par une), j'ai mis ce code:

    NSMutableDictionary * maligne=[NSMutableDictionary dictionaryWithObjectsAndKeys:valeur,@first,nil];
    model=[[NSArray alloc] initWithObjects:maligne,nil];

    tableView:objectValueForTableColumn:row:
    Ben ça donne l'impression (fausse ? ou pas ?) que tu as mis exactement "[tt]tableView:objectValueForTableColumn:row:[/tt]" comme ligne dans ton code, tel quel ?!

    Oui. N'est-ce pas comme cela que l'on demande à  la tableview d'aller lorgner du côté du datasource?
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #37
    dans 1217226380:

    tableView:objectValueForTableColumn:row:
    N'est-ce pas comme cela que l'on demande à  la tableview d'aller lorgner du côté du datasource?

    :) :) ;D    ::)
    Non, en C,la notation LABEL: est une étiquette pour faire des goto

    Exemple :

    extern int printf(char *,...);
    int main(void){
    int a=2;
    goto INCREMENT;

    LA_SUITE :
    printf("%d\n",a);
    goto FIN;

    INCREMENT:
    a++;
    goto LA_SUITE;

    FIN :
      return 0;
    }



    Exécution :
    % gcc pgm.c  -o pgm
    % pgm
    3
    %

  • Philippe49Philippe49 Membre
    15:29 modifié #38

    dans 1217226380:

    tableView:objectValueForTableColumn:row:
    N'est-ce pas comme cela que l'on demande à  la tableview d'aller lorgner du côté du datasource?


    Ces messages sont des demandes réalisées automatiquement par la table view, et seulement quand elle en a besoin. On ne met jamais cet appel dans son code, et si il avait fallu le faire, cela se ferait ainsi :

    id object=
      [ theDatasource
              tableView:theTableView
              objectValueForTableColumn:[theTableView tableColumnWithIdentifier:@the_Identifier]
              row: 1
      ];
  • RocouRocou Membre
    15:29 modifié #39
    dans 1217231116:


    dans 1217226380:

    tableView:objectValueForTableColumn:row:
    N'est-ce pas comme cela que l'on demande à  la tableview d'aller lorgner du côté du datasource?


    Ces messages sont des demandes réalisées automatiquement par la table view, et seulement quand elle en a besoin. On ne met jamais cet appel dans son code

    Donc il suffit d'alimenter le datasource et automatiquement la tableview va y puiser les nouvelles données?

    Mais comment alimenter le datasource?
    Ce code suiffit-il?:
    NSMutableDictionary * maligne=[NSMutableDictionary dictionaryWithObjectsAndKeys:valeur,@first,nil];
    model=[[NSArray alloc] initWithObjects:maligne,nil];


    Mais en l'occurrence, ça ne fonctionne pas. Ma tableview ne se modifie pas.
  • Philippe49Philippe49 Membre
    15:29 modifié #40
    Il faut que le datasource implémente les méthodes :

    -(NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
    {
        return [model count];
    }

    et

    -(id) tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
    {
      id rowObject=[model objectAtIndex:row];
      NSString * identifier=[tableColumn identifier];
      return [rowObject objectForKey:identifier];
    }

    Il faut de plus que dans IB, la colonne 0 ait bien son champ "identifier" valant first et que l'outlet datasource de cette table view (clic droit sur la table view, et connecter datasource) soit connecté à  l'objet que tu utilises pour cela.

  • RocouRocou Membre
    15:29 modifié #41
    dans 1217233094:

    Il faut que le datasource implémente les méthodes :

    -(NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
    {
        return [model count];
    }

    et

    -(id) tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
    {
      id rowObject=[model objectAtIndex:row];
      NSString * identifier=[tableColumn identifier];
      return [rowObject objectForKey:identifier];
    }

    Il faut de plus que dans IB, la colonne 0 ait bien son champ "identifier" valant first et que l'outlet datasource de cette table view (clic droit sur la table view, et connecter datasource) soit connecté à  l'objet que tu utilises pour cela.



    Oui tu m'as déjà  expliqué cela précédemment et ça fonctionne très bien. ce code fonctionne:
    -(void) awakeFromNib
    {
    NSMutableDictionary * model1=[NSMutableDictionary dictionaryWithObjectsAndKeys:@Toto,@first,@Titeuf,@second,nil];
    NSMutableDictionary * model2=[NSMutableDictionary dictionaryWithObjectsAndKeys:@Mommo,@first,@Mimi,@second,nil];
    NSMutableDictionary * model3=[NSMutableDictionary dictionaryWithObjectsAndKeys:@titi,@first,@Riri,@second,nil];

    model=[[NSArray alloc] initWithObjects:model1,model2,model3,nil];
    }


    Ma Tableview affiche bien ces valeurs. Mais je n'arrive pas à  afficher autre chose de façon "dynamique".
    Etant grand débutant, je m'exprime sûrement très mal. Voici un exemple plus simple pour tenter d'expliquer ce que je voudrais:

    for (i=1; i<100; i++)
    {
    Afficher toutes les valeurs de i dans ma tableview (une itération par ligne)
    }


    Comment faire ceci?
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #42
    1) Si tu veux changer les données à  afficher dans la table view, tu changes le model, et tu indiques à  la table view qu'il faut se rafraà®chir.

      NSMutableDictionary * model4=[NSMutableDictionary   dictionaryWithObjectsAndKeys:@Nicolas,@first,@Carla,@second,nil];
      [model replaceObjectAtIndex: 2 withObject:model4];
      [tableView reloadData];
    La troisième ligne indique à  la tableView qu'il faut faire une mise à  jour, et elle se débrouille pour inclure cela dans le runtime.



    2) Si tu veux simplement lire les données affichées, la table view n'intervient pas, tu fais :

    for (i=1; i<[model count]; i++)
    {
       NSLog(@%@",[model objectAtIndex:i]);
    }
    ou plus élégamment
    for(id object in model) {
       NSLog(@%@",object);
    }
  • RocouRocou Membre
    15:29 modifié #43
    dans 1217234765:

    2) Si tu veux simplement lire les données affichées, la table view n'intervient pas, tu fais :

    for (i=1; i<[model count]; i++)
    {
       NSLog(@%@",[model objectAtIndex:i]);
    }
    ou plus élégamment
    for(id object in model) {
       NSLog(@%@",object);
    }


    Arg! Décidément, on ne se comprend pas. Non, je ne veux pas simplement afficher des valeurs, je veux que chaque itération de i soit une ligne de ma tableview.
  • RocouRocou Membre
    15:29 modifié #44
    dans 1217234765:

    1) Si tu veux changer les données à  afficher dans la table view, tu changes le model, et tu indiques à  la table view qu'il faut se rafraà®chir.

      NSMutableDictionary * model4=[NSMutableDictionary   dictionaryWithObjectsAndKeys:@Nicolas,@first,@Carla,@second,nil];
      [model replaceObjectAtIndex: 2 withObject:model4];
      [tableView reloadData];
    La troisième ligne indique à  la tableView qu'il faut faire une mise à  jour, et elle se débrouille pour inclure cela dans le runtime.

    J'obtiens une nouvelle erreur:
    *** -[NSCFArray replaceObjectAtIndex:withObject:]: mutating method sent to immutable object
  • Philippe49Philippe49 Membre
    15:29 modifié #45
    dans 1217235469:

    Arg! Décidément, on ne se comprend pas. Non, je ne veux pas simplement afficher des valeurs, je veux que chaque itération de i soit une ligne de ma tableview.


    Il suffit de modifier un peu le code dans la boucle ...

    for(id object in model) {
      NSLog(@first:%; second:%@", [object objectForKey:@first], [object objectForKey:@second]);
    }


  • Philippe49Philippe49 Membre
    15:29 modifié #46
    dans 1217235685:

    J'obtiens une nouvelle erreur:
    *** -[NSCFArray replaceObjectAtIndex:withObject:]: mutating method sent to immutable object


    Le message d'erreur dit explicitement ce qui ne va pas.
    En Objective-C, certains objets possèdent une classe "immutable" et une classe "mutable". par exemple les chaà®nes de caractères peuvent être définies en version "immutable" NSString, ou en version "mutable" NSMutableString. De même les tableaux ont une version "immutable" NSArray et une version "mutable" NSMutableArray.
    Si on veut pouvoir changer les données d'un tableau il faut prendre la version NSMutableArray.

    Donc
       NSMutableArray * model; // dans les déclarations de variables de ta classe

       model=[[NSMutableArray alloc] initWithObjects:model1,model2,model3,nil];
      // dans la méthode qui initialise le model
  • Philippe49Philippe49 Membre
    15:29 modifié #47
    dans 1217235469:

    Arg! Décidément, on ne se comprend pas. Non, je ne veux pas simplement afficher des valeurs, je veux que chaque itération de i soit une ligne de ma tableview.


    ou alors tu veux que la boucle fasse en sorte que la table view affiche chaque ligne l'une après l'autre ?
    C'est folie, cela ne marche pas comme cela !! Ce n'est pas le rôle du datasource d'afficher sur l'interface graphique, c'est celui de la tableview et à  ma connaissance, il n'y a pas de méthode [tableview reloadRow:i].
  • RocouRocou Membre
    15:29 modifié #48
    dans 1217236701:

    dans 1217235469:

    Arg! Décidément, on ne se comprend pas. Non, je ne veux pas simplement afficher des valeurs, je veux que chaque itération de i soit une ligne de ma tableview.


    Il suffit de modifier un peu le code dans la boucle ...

    for(id object in model) {
       NSLog(@first:%; second:%@", [object objectForKey:@first], [object objectForKey:@second]);
    }




    Non, non, ton code envoie sur la console, le contenu de ma tableview. Mon but est de modifier ma table view.

    Donc j'aimerais que le code:
    for (i=1; i<4; i++)
    {
    Afficher toutes les valeurs de i dans ma tableview (une itération par ligne)
    }


    me donne ceci:
    tableviewbq2.jpg
  • Philippe49Philippe49 Membre
    15:29 modifié #49
    Il y a bien

    - (void)drawRow:(NSInteger)rowIndex clipRect:(NSRect)clipRect

    mais c'est plus pour jouer sur l'apparence de la cellule que sur le contenu (i.e l'objet transmis par le datasource). Cela appelle demande au delegate ce qu'il veut faire sur chaque cellule en lui envoyant le message tableView:willDisplayCell:forTableColumn:row: .
    Bref c'est une autre histoire.
  • Philippe49Philippe49 Membre
    15:29 modifié #50
    dans 1217237995:

    Donc j'aimerais que le code:
    for (i=1; i<4; i++)
    {
    Afficher toutes les valeurs de i dans ma tableview (une itération par ligne)
    }



    Ah oui, je n'y étais pas du tout, autant pour moi  :)

    -(void) awakeFromNib
    {
       NSMutableDictionary * model1=[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber number WithInt:1],@first,@Titeuf,@second,nil];
       NSMutableDictionary * model2=[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber number WithInt:2],@first,@Mimi,@second,nil];
       NSMutableDictionary * model3=[NSMutableDictionary dictionaryWithObjectsAndKeys:[NSNumber number WithInt:3],@first,@Riri,@second,nil];   

       model=[[NSMutableArray alloc] initWithObjects:model1,model2,model3,nil];
    }




  • Philippe49Philippe49 Membre
    15:29 modifié #51
    Ou si tu tiens à  le faire dans une boucle :

    NSInteger i;
    for(i=0;i<[model count];i++){
      id rowObject=[model objectAtIndex:i];
      [rowObject setObject:[NSNumber numberWithInteger:i] forKey:@first];
    }

    (et là  model n'a pas besoin d'être mutable)
  • RocouRocou Membre
    15:29 modifié #52
    dans 1217238524:

    Ou si tu tiens à  le faire dans une boucle :

    NSInteger i;
    for(i=0;i<[model count];i++){
      id rowObject=[model objectAtIndex:i];
      [rowObject setObject:[NSNumber numberWithInteger:i] forKey:@first];
    }

    (et là  model n'a pas besoin d'être mutable)

    Voilà !  :adios!:

    Cela dit, la tableview n'est pas rafraà®chie, je dois cliquer sur une autre fenêtre pour que le rafraà®chissement se fasse...

    Bon et maintenant que tu sais ce que je voudrais, en reprenant mon code initial (car ce que je veux, ce n'est évidemment pas une itération de "i" mais le contenu d'un Dictionnary). j'ai essayé de faire ceci mais ça ne passe même pas à  la compilation:

    for(NSDictionary * fiche in result)
    {

    id rowObject=[model objectAtIndex:[fiche valueForKey: @client]];
          [rowObject setObject:[NSString [fiche valueForKey: @client]] forKey:@first]; 

    }


    sachant que ceci fonctionne:

    for(NSDictionary * fiche in result)
    {

    NSLog(@Cette fiche a %@ pour client." , [fiche valueForKey: @client]);
    }

  • Philippe49Philippe49 Membre
    15:29 modifié #53
    dans 1217241244:

    Cela dit, la tableview n'est pas rafraà®chie, je dois cliquer sur une autre fenêtre pour que le rafraà®chissement se fasse...

    Il faut rajouter [tableview reloadData] pour que la table view s'auto rafraichisse !
    for(....){
    }
    [tableview reloadData];

    Lorsque tu provoques un événement comme cliquer sur une autre fenêtre, puis tu recliques sur la fenêtre de ton appli, celle-ci se rafraichit entièrement, et en particulier la tableview.
  • RocouRocou Membre
    15:29 modifié #54
    dans 1217241564:

    dans 1217241244:

    Cela dit, la tableview n'est pas rafraà®chie, je dois cliquer sur une autre fenêtre pour que le rafraà®chissement se fasse...

    Il faut rajouter [tableview reloadData] pour que la table view s'auto rafraichisse !
    for(....){
    }
    [tableview reloadData];

    Lorsque tu provoques un événement comme cliquer sur une autre fenêtre, puis tu recliques sur la fenêtre de ton appli, celle-ci se rafraichit entièrement, et en particulier la tableview.


    Non, [tableview reloadData]; est présent dans mon code, juste après la boucle. J'aurais du le préciser.
  • Philippe49Philippe49 Membre
    15:29 modifié #55
    dans 1217241244:

    Bon et maintenant que tu sais ce que je voudrais, en reprenant mon code initial (car ce que je veux, ce n'est évidemment pas une itération de "i" mais le contenu d'un Dictionnary). j'ai essayé de faire ceci mais ça ne passe même pas à  la compilation:

    for(NSDictionary * fiche in result)
    {

    id rowObject=[model objectAtIndex:[fiche valueForKey: @client]];
          [rowObject setObject:[NSString [fiche valueForKey: @client]] forKey:@first]; 

    }


    sachant que ceci fonctionne:

    for(NSDictionary * fiche in result)
    {

    NSLog(@Cette fiche a %@ pour client." , [fiche valueForKey: @client]);
    }




    Déjà , [model objectAtIndex:[fiche valueForKey: @client]]; ne peut pas passer. Après objectAtIndex: on attend un NSInteger. Il faut donc remplacer par l'indice.
    NSUInteger row=[model indexOfObject:fiche];

    [NSString [fiche valueForKey: @client]] cela ne veut rien dire
    [rowObject setObject:[fiche valueForKey: @client] forKey:@first];  
  • Philippe49Philippe49 Membre
    15:29 modifié #56
    dans 1217241845:

    Non, [tableview reloadData]; est présent dans mon code, juste après la boucle. J'aurais du le préciser.


    Là , c'est bizarre
  • RocouRocou Membre
    15:29 modifié #57
    dans 1217241911:


    Déjà , [model objectAtIndex:[fiche valueForKey: @client]]; ne peut pas passer. Après objectAtIndex: on attend un NSInteger. Il faut donc remplacer par l'indice.
    NSUInteger row=[model indexOfObject:fiche];

    [NSString [fiche valueForKey: @client]] cela ne veut rien dire
    [rowObject setObject:[fiche valueForKey: @client] forKey:@first];  



    Oui, je comprends peu à  peu. Mon code fonctionne presque, j'ai encore deux problèmes.

    [size=10pt]
    NSInteger i=0;
    while (![rs isEOF])
                      {
      [result addObject:[rs dictionaryFromRecord]];
          NSString* valeur = [[result objectAtIndex:i] valueForKey:@client];
     
        id rowObject=[model objectAtIndex:i];
                            [rowObject setObject:valeur forKey:@first];

                         
     
                          // NSLog(@Cette fiche a %@ pour client.", valeur);
     
                          i++;
                          [rs moveNext];
                      }   
        [tableView reloadData];
    [/size]

    Ma tableview contient enfin mes valeurs.
    Cependant:
    1- Elle n'en contient que 4 et j'obtiens l'erreur suivante à  l'exécution:
    *** -[NSCFArray objectAtIndex:]: index (4) beyond bounds (4)
    Je pense avoir compris pourquoi car dans le bloc awakeFromNib, seules 4 lignes sont allouées:
    -(void) awakeFromNib<br />{<br />	NSMutableDictionary * model1=[NSMutableDictionary dictionaryWithObjectsAndKeys:@&quot;toto&quot;,@&quot;first&quot;,nil];<br />	NSMutableDictionary * model2=[NSMutableDictionary dictionaryWithObjectsAndKeys:@&quot;titi&quot;,@&quot;first&quot;,nil];<br />	NSMutableDictionary * model3=[NSMutableDictionary dictionaryWithObjectsAndKeys:@&quot;riri&quot;,@&quot;first&quot;,nil];	<br />	NSMutableDictionary * model4=[NSMutableDictionary dictionaryWithObjectsAndKeys:@&quot;loulou&quot;,@&quot;first&quot;,nil];	<br />	model=[[NSArray alloc] initWithObjects:model1,model2,model3,model4,nil];<br />}
    


    Alors comment allouer dynamiquement model?

    2- toujours ce problème de rafraà®chissement
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #58
    dans 1217242852:

    Alors comment allouer dynamiquement model?

    Il faut que model soit défini par NSMutableArray * model; si tu veux pouvoir changer le nombre d'objets dans ton modèle, et l'initialisation est alors à  faire ainsi dans awakeFromNib :

    -(void) awakeFromNib
    {
    NSMutableDictionary * model1=[NSMutableDictionary dictionaryWithObjectsAndKeys:@toto,@first,nil];
    NSMutableDictionary * model2=[NSMutableDictionary dictionaryWithObjectsAndKeys:@titi,@first,nil];
    NSMutableDictionary * model3=[NSMutableDictionary dictionaryWithObjectsAndKeys:@riri,@first,nil];
    NSMutableDictionary * model4=[NSMutableDictionary dictionaryWithObjectsAndKeys:@loulou,@first,nil];
    model=[color=navy][b]NSMutableArray[/b][/color] alloc] initWithObjects:model1,model2,model3,model4,nil];<br />}<br /><br />En effet, [color=navy][b][result addObject:[rs dictionaryFromRecord;[/b][/color] ne peut se faire que si result est "mutable"

  • Philippe49Philippe49 Membre
    15:29 modifié #59
    dans 1217242852:

    Toujours ce problème de rafraà®chissement

    Ce problème est illogique.
    • As-tu bien un IBOutlet NSTableView * tableView; comme variable d'instance de la classe qui contient ce code ?
    • Il existe sans doute dans le nib une instance de cette classe. Clic droit sur cette instance dns IB, est-ce que la connexion avec la table view est faite ?

  • Philippe49Philippe49 Membre
    15:29 modifié #60
    dans 1217242852:

    [size=10pt]
    NSInteger i=0;
    while (![rs isEOF])
                       {
      [result addObject:[rs dictionaryFromRecord]];
          NSString* valeur = [[result objectAtIndex:i] valueForKey:@client];
       
        id rowObject=[model objectAtIndex:i];
                            [rowObject setObject:valeur forKey:@first];

                           
       
                          // NSLog(@Cette fiche a %@ pour client.", valeur);
       
                           i++;
                           [rs moveNext];
                       }     
        [tableView reloadData];
    [/size]



    1) De la précaution
    Pour que les indices i correspondent bien, il faut que result ne contienne aucun élément. Si il y a des risques que cela ne soit pas le cas, il serait prudent de faire l'instruction [result removeAllObjects]; avant la boucle while  (ou [model removeAllObjects] compte-tenu de ce qui suit)

    2) De l'harmonie

    Change l'identifier "first" en "client" et le bloc d'instructions :
       [result addObject:[rs dictionaryFromRecord]];
       NSString* valeur = [[result objectAtIndex:i] valueForKey:@client];
       id rowObject=[model objectAtIndex:i];
       [rowObject setObject:valeur forKey:@first]; 

    peut se remplacer par :
       id rowObject=[rs dictionaryFromRecord];
       [model addObject:rowObject];

    et result devient à  priori inutile.  
  • Philippe49Philippe49 Membre
    juillet 2008 modifié #61
    Ce qui fait un code :

    @interface .......... {
      NSMutableArray * result;
    }
    ..
    @end

    @implementation ..
    -(void) awakeFromNib
    {
       model=[[NSMutableArray alloc] init];
    }

    ............
    [model removeAllObjects];
    while(![rs isEOF]){
       id rowObject=[rs dictionaryFromRecord];
       [model addObject:rowObject];
       [rs moveNext];
    }
    [tableView reloadData];


Connectez-vous ou Inscrivez-vous pour répondre.