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.
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 ?!
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?
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 ];
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.
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.
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];
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) }
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); }
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.
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
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 ...
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
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].
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 ...
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.
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:
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.
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.
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:
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];
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.
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:
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 :
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 ?
[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];
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];
Réponses
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à . :-\\
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;
Oui. 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
%
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
];
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.
-(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?
 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);
}
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.
J'obtiens une nouvelle erreur:
*** -[NSCFArray replaceObjectAtIndex:withObject:]: mutating method sent to immutable object
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]);
}
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
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].
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:
- (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.
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];
}
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]);
}
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.
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];
Là , c'est bizarre
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:
Alors comment allouer dynamiquement model?
2- toujours ce problème de rafraà®chissement
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"
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 ?
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.Â
@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];