[Résolu] Ajouter une ligne dans un tableau

PierrePierre Membre
mai 2010 modifié dans API UIKit #1
Je cherche à  faire quelque chose qui a priori est super simple mais je bloque sans comprendre pourquoi :

J'ai le code suivant :

(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {<br />	return [stories count];<br />}


stories est déclaré comme un NSMutableArray et me renvoie 2 (normal il contient 2 éléments).

Mon tableau contient une première cellule spécifique qui va renvoyer des informations et ensuite n cellules avec les informations contenues dans stories. (n étant égale au nombre d'éléments dans stories).

J'ai donc écrit le code suivant :
(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {<br />	return [stories count]+1;<br />}


Qui me renvoie l'erreur suivante à  l'exécution :
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (2) beyond bounds (2)'


J'ai donc essayé comme ceci :
// Customize the number of rows in the table view.<br />- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {<br />	NSInteger *numberOfRows = [stories count] + 1;<br />	[numberOfRows autorelease];<br />	return numberOfRows;<br />}


Qui plante sans renvoyer d'erreurs.

Qu'est-ce que je ne fait pas correctement ? Est-ce que vous avez une idée de comment faire pour que ça fonctionne ?

Merci d'avance pour vos lumières,
Pierre

Réponses

  • AliGatorAliGator Membre, Modérateur
    15:53 modifié #2
    Ce n'est pas ce code qui fait planter l'appli, mais cellForRowAtIndexPath.
    En effet, maintenant tu renvoies 3 au lieu de 2, mais j'imagine que tu n'as pas modifié ton cellForRowAtIndexPath qui va toujours chercher l'élément n°indexPath.row de ton tableau "stories"... donc comme tu lui as dit qu'il y avait 3 lignes, si tu n'as pas changé ton implémentation il demande l'élément 0, puis l'élément 1, et... l'élément 2

    il faut que tu adaptes ton code cellForRowAtIndexPath pour que si indexPath.row == 0 alors tu mets ta cellule spéciale, sinon, tu mets tes cellules avec le contenu de l'élément...indexPath.row-1 de stories, du coup
  • CéroceCéroce Membre, Modérateur
    15:53 modifié #3
    dans 1273830941:

    J'ai donc essayé comme ceci :
    // Customize the number of rows in the table view.<br />- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {<br />	NSInteger *numberOfRows = [stories count] + 1;<br />	[numberOfRows autorelease];<br />	return numberOfRows;<br />}
    



    NSInteger n'est pas un objet.
    Il faut que tu révises tes cours de C, la partie sur les pointeurs.
  • PierrePierre Membre
    15:53 modifié #4
    @AliGator : merci, je comprend mieux le problème. Je vais essayer d'adapter le code en fonction de ce que tu m'as dit.

    @Céroce : si mes souvenirs sont bons "NSInteger" n'existe pas en C (j'espère que je dit pas de connerie ^^) mais seulement en Objective-C. Je savait pas que ce n'est pas un objet.

    Je ne voit pas le rapport avec les pointeurs, j'ai sûrement écrit une grosse co**erie mais je ne voit pas laquelle, peut-tu éclaire ma lanterne ? :)

    Merci pour votre aide,
    Pierre
  • lgriffielgriffie Membre
    mai 2010 modifié #5
    Céroce à  raison ton code à  une erreur dans cette ligne

    NSInteger *numberOfRows = [stories count] + 1;<br />[numberOfRows autorelease];
    


    tu devrais avoir

    NSInteger numberOfRows = [stories count] + 1;<br />[numberOfRows autorelease]; // Supprimer cette ligne sinon cela va planter
    


    Car NSInteger n'est pas un objet donc tu ne peux pas faire une référence par pointeur sur un "non objet" ;) D'ailleurs la méthode le précise. Les NSInteger ne sont pas des pointeurs.

    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    

  • ChachaChacha Membre
    15:53 modifié #6
    >si mes souvenirs sont bons "NSInteger" n'existe pas en C
    Effectivement. Mais si tu fais un "command-clic-clic" dessus, tu auras vite l'explication
    [pre]#if __LP64__ || NS_BUILD_32_LIKE_64
    typedef long NSInteger;
    typedef unsigned long NSUInteger;
    #else
    typedef int NSInteger;
    typedef unsigned int NSUInteger;
    #endif[/pre]

    C'est un simple typedef qui permet d'uniformiser le code selon qu'on est en 32 ou 64 bits. En effet, le modèle 64 bits choisi par Apple est le LP64 : les long et les pointeurs passent en 64 bits, mais pas les int. NSInteger permet donc d'uniformiser le code pour les deux environnements.
  • PierrePierre Membre
    15:53 modifié #7
    @Chacha : merci pour l'information. Je ferais plus souvent cmd+clic dorénavant. :D

    @lgriffie : ok je comprend mieux ce que dit @Céroce maintenant. C'est bien la ligne :
    [numberOfRows autorelease];
    
    qui faisait planter mon code.

    Ensuite "cellForRowAtIndexPath" me renvoie l'erreur :
    Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (2) beyond bounds (2)'
    que j'ai tout de suite corrigé avec l'aide de @AliGator ! o:)

    Donc maintenant ça marche, merci à  tous !

    Pierre
  • AliGatorAliGator Membre, Modérateur
    mai 2010 modifié #8
    Pomme-Double-Clic sur NSInteger dans ton code, tu vas mieux comprendre de quoi il s'agit :P
    Donc en un sens, si, le type qui se cache derrière NSInteger (puisque c'est un typedef) existe en C.

    Le rapport avec les pointeurs ? Tu utilises NSInteger comme si c'était un objet Cocoa, avec la notation pointeur (la petite étoile) : "NSInteger*".

    Au final ton code :
    1) récupère [tt][stories count]+1[/tt] (donc des valeurs comme 3 ou 4), qui est un NSInteger (type retourné par la méthode "count" de NSArray)... dans un pointeur NSInteger* (donc une adresse mémoire sensée pointer vers un NSInteger) au lieu de récupérer la valeur directement... déjà  il y a une erreur de type qui doit t'être signalée par un warning à  ce niveau (genre "implicit cast from integer to pointer" ou un truc dans ce goût là )

    2) tu envoies un message autorelease à  ce NSInteger*, donc à  cette adresse mémoire 0x00000003 ou 0x00000004 (donc il s'attend à  y trouver un objet Cocoa à  qui envoyer ce "autorelease", alors qu'à  cette adresse mémoire je sais pas ce qu'il y a mais certainement pas ce que tu y attend... y'a déjà  des chances que ça plante ici)... tu devrais déjà  avoir un 2e warning te disant que "NSInteger" n'est pas un NSObject, ou que "NSInteger* may not respond to autorelease", ou un truc comme ça, enfin un warning t'indiquant que tu ne devrais pas à  envoyer de message autorelease à  un truc qui n'est pas un NSObject.

    3) et en plus après tu retournes un type de données "NSInteger*" en sortie de ta méthode, alors que le type de retour attendu est juste "NSInteger"... et tu devrais donc avoir un 3e warning t'indiquant ce problème de non-correspondance de type de retour.


    Donc avec ces 3 warnings, un warning sur chaque ligne de ta méthode "tableView:numberOfRowsInSection:", ça aurait dû te poser des questions et te mettre sur la voie avec tout ça !
  • PierrePierre Membre
    15:53 modifié #9
    @AliGator : merci pour tout ces détails, mais avant aujourd'hui les "warnings" que tu cite n'étaient pas affichés. Ce matin en relançant XCode il y avait bien des "warnings". :)

    J'ai encore appris un truc sur l'objective-C aujourd'hui. (mode:faut pas rêver non plus) Si ça se trouve je vais finir dieux du code.(/mode:faut pas rêver non plus)

    En tout cas merci pour votre patience et vos explication de qualités.

    Je retourne à  mon code,
    Pierre
Connectez-vous ou Inscrivez-vous pour répondre.