[debutant] aide pour détail de tableView
Bonjour,
je sais qu'avant de demander de l'aide sur le forum, il faut avoir fait ses devoirs et j'ai conscience d'être très, très débutante... mais je m'essaie en espérant au moins écrire une question cohérente ;-)
J'essaie depuis une semaine de d'intégrer une vue de détail liée aux données d'une tableview.
Touts les livres ou tutos consulté, soit s'arrete après la tableview (et en tableview contrôler) soit sont d'une version trop ancienne pour fonctionner. Je me suis procurer un modèle qui fonctionne, qui correspond a ce que j'ai besoin... mais il utiles des nib et j'arrive pas a appliquer en contexte storyboard pour être en mesure de faire la suite de l'application selon mes besoins.
J'essaie de me retrouver dans la documentation de apple, ...e t je m'y perd carrément.
voile ou j'en suis rendu:
J'ai ma tableview fonctionnelle, les données provenant d'un array dans le ViewController.m (déjà je me demande si je serai pas mieux de le mettre dans une classe a part, mais c'est pas ma question principale ici)
Je creer un autre ViewController, je creer une classe DetailViewController, je fais un segue entre la cellule et cette vue.
Je vois dans la documentation de apple un code pour définir le segue pour "passing data to a destination view controller" .... mais je comprend pas ou je dois mettre ce code!
bon, y'a bien d'autre chose que je comprend pas, mais deja si j'arrivais a situer ce bout, je pense que j'avancerais.
de la documentation sur le sujet serait aussi apprécié ;-)
Réponses
Peux-tu être un petit plus précise ? En particulier, de quel code parles tu ? Peux-tu poster le code que tu cherches à positionner, et ton code existant ? Cela permettra de t'aider un peu mieux...
Bonjour Alf,
voici ce que j'Ai trouvé dans la documentation de Apple, :
Listing 3-1 Passing data to a destination view controller
je suppose, mais j'en suis pas sur, que je dois l'inclure.
mon code... ben lequel justement? Celui de ViewControler.m? ... je mets celui-la...:
#import "ViewController.h"
#import "CustomCellTableViewCell.h"
@interface ViewController ()
{
NSArray*MyArray;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
MyArray = [[NSArray alloc] initWithObjects:@un,@deux,@trois, nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return MyArray.count;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @MyCell;
CustomCellTableViewCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!Cell)
{
Cell = [[CustomCellTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Cell.MyLabel.text = [MyArray objectAtIndex:indexPath.row];
return Cell;
}
@end
ho j'avance!
j'ai trouve un exemple ou j'ai pu voir que c'a allait bien a la fin du ViewController.m.
ok, il reste a tout ajuster car pour le moment mon appui plante, mais j'ai espoir de trouver ou ;-)'
après je me mettrait a la tache d'apprivoiser les Array un peu plus pour avoir plus d'un item par range.
he ben non, j'arrive pas a deboguer, du moins jusqu'au bout. L'appui s'ouvre maintenant, le tableView s'affiche, tout est beau jusqu'a ce que je clique sur une cellule.
j'a ai vu dans les note que le code sur le segue pourrait aussi être a mettre dans le detailViewController.m, donc je revis au point de e matin: je sais pas ou le mettre, mais en plus, je ne comprend pas le dernier élément que je dois y mettre.
mon code viewController.m est actuellement
#import "ViewController.h"
#import "CustomCellTableViewCell.h"
#import "DetailViewController.h"
@interface ViewController ()
{
NSArray*MyArray;
}
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
MyArray = [[NSArray alloc] initWithObjects:@un,@deux,@trois, nil];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return MyArray.count;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @MyCell;
CustomCellTableViewCell *Cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(!Cell)
{
Cell = [[CustomCellTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
Cell.MyLabel.text = [MyArray objectAtIndex:indexPath.row];
return Cell;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@showDetail]) {
NSIndexPath *indexPath = [self.myTableView indexPathForSelectedRow];
NSDate *object = MyArray[indexPath.row];
ERREUR SUR CETTE LIGNE en turquoise [[segue destinationViewController] setDetailItem:object];
}
}
/*
// version d'un appli base sur modele master/detail:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:@ShowDetails]) {
DetailViewController *detailViewController = [segue destinationViewController];
NSIndexPath *indexPath = [self.myTableView indexPathForSelectedRow];
detailViewController.data = [self.detailItem objectInListAtIndex:indexPath.row];
}
}
*/
/*- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
NSDate *object = MyArray[indexPath.row];
self.detailViewController.detailItem = object;
}
}
*/
@end
1. Essayes de mettre des balises "code" lorsque tu joins du code, ce sera plus lisible.
2. Attention aux conventions de nommage (première lettre en majuscule pour les classes, et en minuscule pour les instances). Ex :
pour ton array, mets plutôt "NSArray*myArray;"
3. la méthode prepareForSegue doit effectivement être mise dans ViewController.m ; l'emplacement (début/fin) a peu d'importance. Tu le mets ou tu veux, c'est juste une question de lisibilité.
4. Dans ton storyboard, tu dois bien avoir le segue avec le même nom que dans ton test du prepareForSegue (ici showDetail, attention aux minuscules/majuscules)
5. Pour l'erreur, çà me parait normal, car tu n'as pas des dates mais des NSString dans ton array ; essaye ceci :
Merci Alf,
je n'Ai plus de message d'erreur dans le code du segue.
par contre mon appui bug encore ;-) selon le lot de deboguage, le problème est dans le DetialViewController maintenant, ouf, j'ai encore beaucoup de travail, moi qui pensant avoir un tout petit projet tout simple ;-)
Qu'est ce que tu veux dire pas mettre des balises "code" quand je joins du code ? <code> ?? (il me semble qu'en HTML, balise c'est < >) et a mettre la ou j'ajoute des bouts ?
ok pour les minuscules, ce qui est bon signe pour ma compréhension, c'est que j'avais été étonnée de voir une majuscule la dans le tuto qui m'a aide.
Pour mettre les balises code, tu cliques sur le bouton "<>", et tu verras apparaitre une fenêtre dans laquelle tu copies ton code, cela permet une meilleure lisibilité à l'écran.
Sinon, pour ton debogage, quel message d'erreur as tu ? ou quel comportement ?
Car évidemment, dans le DetailViewController, il faut que tu affiches l'objet qui a été sélectionné dans le MasterViewController...
Edit : Ne t'inquiètes pas, c'est normal, même pour un petit projet de patauger au départ. Ce qui est important, c'est d'en profiter pour acquérir les bases proprement. Donc, ne pas hésiter à poster le code que tu essayes, même si celui ci ne te parait pas très joli ! Le ridicule ne tue pas !
Merci autant de tes réponses que de tes encouragements Alf :-)
Bon j'essaie de me recomprendre dans mon code, car, hier, en essayant plein de chose, j'ai fini pas y ajouter des bouts pris ailleurs et la j'ai du mal a m'y retrouver .... bref, j'ai du mal a clarifier quel est l'objet en question, sélectionner dans mon ViewController.m (et pas dans un MasterViewControler) et que je dois afficher dans DetailViewContrioller. Je pensais que c'était mon detalItem mais ça ne semble pas être ça...
je fais une peu de ménage dans tous cela, puis je posterai mon code.
Bonjour,
Alors effectivement comme te l'a dit Alf, tu travailles avec un array de NSString :
Et puis, curieusement tu décides que ton array contient des NSDate :
Dernière petite chose : tu sembles travailler avec Storyboard. De fait cette partie de code :
n'est pas utile. Ta cell ne sera jamais à nil.
Ce n'est pas du tout une question de Storyboard ou pas Storyboard.
Ca dépend de la méthode utilisée pour demander une cellule recyclée, l'ancienne méthode ou la plus moderne.
Quand tu auras digéré le pavé (très instructif comme toujours) d'AliGator, tu pourras te replonger dans ton DetailViewController.
Tu dois avoir une propriété detailItem, qui doit être de type NSString (puisque tu as dans ton prepareForSegue, setDetailItem:object, avec object de type NSString), et qui va contenir ce qui a été sélectionné dans ton ViewController.
Pour l'afficher, tu dois le faire généralement dans le viewDidLoad, et tu peux par exemple l'afficher dans un UITextField ou un UILabel, de ton DetailViewController ; çà devrait donner un truc du genre :
où myLabel est un UILabel de ton DetailViewController (attention de bien connecter l'IBOutlet).
Voilà , n'hésites pas à demander si tu as encore besoin...
Re-bonjour,
merci de vos commentaires a tous, ça encourage de plus être seule!
D'abord, pour le passe de date a string, j'avais fait un essaie en recopiant le version de preparerForSegue pris dans ce que génère Xcode quand on demande une base de type Master/details ... et je n'avais pas réalisée qu'il y était question de date! Mais a la base, si j'ai essaye ce code a la place de ce que je voyait de la documentation de Apple, c'est parce que je n'arrivais a a identifier les éléments d'une écriture pointée, et j'avais mélangé les deux versions de codes par al suite. ce matin j'ai fini pas m'y retrouver sur ce point, j'ai remis le code venant de la documentation, avec les bons éléments aux bonnes places, je pense.
Pour la modernisation de l'innitialisation des cellules, sans nil, je trouve super intéressant les explications que tu donnes Ali, mais je n'ai pas réussi a la appliquer! Je pense que je n'Ai pas assez de compréhension des arrays pour cela, actuellement je focuse sur le DetailViewController, ensuite je me plongerai dans les arrays... s'aurais sûrement été plus logique de faire l'inverse ;-)
Alf, tu m'éclaire beaucoup, ça avance,mais ça bogue encore.
c'est une erreur de type SIGABRT
​quand je met un breakpoint, le début du lot d'erreur comporte:
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<DetailViewController 0x8f91410>
​... mais le message est beaucoup, beaucoup plus long.
j'ai fais du ménage dans mon code, et mis des commentaires pour m'y retrouver car je suis loin d'avoir tout mémoriser suffisamment.
actuellement voici mes deux fichier, ViewController.m et DetailViewController.m
la je travail a voir si j'ai déclarée correctement mon detailItem...
Attention, dans ViewController, dans le prepareForSegue, ce n'est pas detailItemLabel que tu dois renseigner, mais bien detailItem (NSString), car le label n'existe pas encore (la vue n'est pas encore chargée... donc le label non plus). C'est pour çà qu'on le fait dans le viewDidLoad du DetailViewController...
Sinon, si çà plante encore, peux tu mettre tout le message d'erreur ?
Ha la ça m'interresse fort ce que tu dis la Alf,
moi je ne mettais que des labels ou variables déjà déclarées!!!!!
ok, je comprend mieux quelque chose qui parle de cela dans un de mes livre, je boss la dessus donc,
Merci!
Heuu non. Je me trompe peut-être mais l'automatic cell loading est implicite avec le Storyboard (mais c'est vrai qu'on peut l'utiliser sans le Storyboard). Ce qui fait que la méthode dequeueReusableCellWithIdentifier: ne renverra jamais nil dans son cas.
Dans la doc de la méthode dequeueReusableCellWithIdentifier :
This method dequeues an existing cell if one is available or creates a new one using the class or nib file you previously registered. If no cell is available for reuse and you did not register a class or nib file, this method returns nil.
Dans le table view programming guide :
Because the prototype cell is defined in a storyboard, the dequeueReusableCellWithIdentifier: method always returns a valid cell. You don't need to check the return value against nil and create a cell manually.
Usant...
En passant, j'adore les chien ;-)
Donc je supprime tout simple le la ligne if (!cell) sans modifierai le reste du code?
Ouaf !
Toute la condition if (!cell) { ...blablabla...} n'est pas utile (elle sera toujours fausse). Tu peux la supprimer (en espérant que tu aies saisi un peu le pourquoi du comment).
Merci,
oui je crois biens avoir compris ;-)
et j'en prend bonne note.
Bon...
Grand merci Alf!
tu me fais voir ce que je comprend pas... je le comprend toujours pas mais au moins je vois c'est quoi que je comprend pas (ouf)
J'ai relu les premiers chapitres de mon livre principal (celui de Michel Martin).
Je vois que mon appli est en train de devenir un beau bordel car je ne distingue plus assez les variable, les méthodes et les objets, ce qui appel quoi et le renvoie à quoi ;-)
mais le positif, c'est que je pense que je suis à la charnière de comprendre le principe de l'Objective C avec tout ça ;-)
Bon, dans mon appli, c'est clair que je ne saisi pas les ajustements que je dois faire dans le PrepareForSegue. Alors je vais commencer par vérifier ce que j'en comprend!
J'ai trouvé plusieurs version de ce code.... que je compare entre-deux pour essayer de comprendre, d'Autant que celui dans la documentation de Apple est en écriture pointé.
Alors j'essaie de traduire et commenter, dis moi si je suis dans le champs!
Alors, est-ce que je suis dans le champs???
En quelques mots :
Tu vas appeler à un moment donné performSegueWithIdentifier.
Ton app va regardé si tu as une méthode prepareForSegue:sender.
Si c'est le cas, elle va passer dedans, sinon, elle va effectuer le changement de contrôleur.
Du coup, déclarer prepareForSegue:sender permet de pré-charger des variables du contrôleur qui va apparaà®tre.
Donc, le premier truc, c'est d'identifier le segue.
En effet, on peut très bien imager que si j'appuie sur le bouton1, je veuille aller vers le controller1 et si j'appuie sur le bouton2, d'aller vers le controller2.
D'où la ligne if ([[segue identifier] isEqualToString:@ZzZ]).
Ici, à la place de ZzZ, il faut mettre exactement le nom renseigné dans l'interface builder. Donc c'est case sensitive (majuscule, minuscule, etc.)
Ensuite, il faut récupérer le prochain contrôleur : NextControllerClass *nextController = [segue destinationViewController];
Donc, maintenant que tu as récupérer le prochain contrôleur, il faut faire quelques settings dessus.
Dès lors, si tu as déclarer les bonnes variables, tu les affectes :
nextController.myVariable1 = ZzZ;
Donc, dans le code précédent, tu récupères l'indexPath souhaité (celui sélectionné).
Et grâce à ce dernier, connaissant comment tu as construit ta table en fonction des indexPath et de detailsItem, tu set le data du detailViewController.
Et ensuite, le prochain controller apparaà®t.
Alors, je vais essayer d'être aussi claire que pourrait l'être notre grand maà®tre Ali (là c'est pas gagné !)
Le prepareForSegue est la méthode qui est exécutée avant "d'aller ouvrir la vue suivante", elle ne retourne rien, mais tu y affectes des variables de ta future vue :
- en tout premier, tu testes le segue, car pour ton ViewController, tu peux avoir plusieurs segue différents (ici tu n'as que showDetail, mais tu pourrais avoir d'autres segue)
- ensuite, tu crées une instance detailViewController, de classe DetailViewController
- tu dois ensuite renseigner les propriétés de cette nouvelle instance. Par exemple, si tu as sélectionné l'objet numéro 2 de ta liste, tu vas dire à ta seconde vue, je veux montrer les détails de l'objet numéro 2.
Dans ton cas, ton modèle est extrêmement simple (un array de NSString), et donc, tu dois avoir une propriété de type NSString dans ta classe DetailViewController, que tu peux appeler comme tu veux, disons, mySelectedObject, qui sera déclarée comme ceci :
Et alors, dans ton prepareForSegue, tu auras :
Après, dans ta classe MyDetailViewController, tu vas afficher ton objet sélectionné, ici, vu que c'est un simple NSString, il te suffit d'avoir un label, et de le renseigner au début :
dans le viewDidLoad de ton MyDetailViewController :
C'est vraiment un marteau pilon pour écraser une mouche, mais évidemment, ceci peut s'appliquer à des objets nettement plus complexes qu'un NSString, et là , cela aura un vrai intérêt.
Edit : bon apparemment Larme a été plus rapide que moi !
Merci a tous les deux,
Bon, en vous lisant, il me semble que j'avais a peu près bien compris, en gros c'est ce que je pensais que c'a faisait,
et je vois que j'avais mis les bons noms au bonnes place dans mes essaies.... le problème c'est que c'a marche pas ;-) Donc mon (ou mes) erreur est ailleur.
ha, dire que Xcode me fais tout ça tout seul si je prend un TableViewController au lieu d'un tableView!!!! faut vraiment que je tienne l'apparence graphique, mais bon, à la base, je suis infographiste, du moins je l'étais mais je n'en fais plus que pour mes besoin ça moi! Et puis je veux comprendre.
Bon je reviens a mon appli,
la deux choses:
1- quand je met self.myArray (c'est le nom de mon tableau a moi), j'ai message d'erreur disant qu'il n'y a pas de propriété my array de type ViewController... .... est-ce qu'on doit déclarer un array dans l .h? Moi je l'ai juste défini dans le .m (jusqu'à maintenant, j'avais tout bonnement enlevé le self.)
2- je me demande si je m'y prend de la bonne façon pour créer l'instance ViewController.... en fait j'ai pas ça dans mes livres... je me suis fier a des tutus vidéos... j'ai créer nouveau fichier C, indiquant DetailViewController sous classe de ViewController.... est-ce que c'est cela que je devais faire?
Alf, tu dis: C'est vraiment un marteau pilon pour écraser une mouche, mais évidemment, ceci peut s'appliquer à des objets nettement plus complexes qu'un NSString, et là , cela aura un vrai intérêt.
ben oui c'est l'intérêt j'ai quand même pas l'intention de faire tout cela juste pour lister un, deux trois ;-) Mais je me suis dis que si je compliquait le array en même temps, j'allais me perdre très certainement, alors je clarifie une chose èa la fois, ensuite je passerai a autre chose qu'un simple tableau de NSString. En fait, c'est destinée a des audio, mais je me donne du temps avant d'aborder ce point là ;-), pour le moment, si j'Affiche des données string, je vais déjà être bien contente!. Et quand je vais aborder la manipulation des audio, je vais commencer par les lier a des simple bouton avant de les intégrer dans un tableau et un DetailViewController!. Mais le but, c'est de tout mettre c'a ensemble.
Sinon, pour tes erreurs le mieux serait que tu postes ton projet complet, on pourrait mieux t'expliquer ce qui ne va pas....
Le but n'est pas de te faire le travail hein mais vu que tu tournes en rond depuis un moment... ce serait plus simple de t'aider à corriger ton projet plutôt que de le faire de A à Z.
Alf, je ne l'ai pas du tout pris comme un reproche, au contraire, que tu comprend bien pourquoi je me donne ce mal pour un si petit tableau ;-)
poster tout le projet? je fais comment??
reste que je pense le refaire de A a Z car je constate que, dans les liste de Outlet, les nom sont resté ceux que j'avais donnés au tout début. Mais la je pense que je reproduis tout le temps les mêmes erreurs.
T'inquiète pas, je compte pas faire faire le travail a ma place, pour ça, j'engagerais un programmeur... et j'essaierais surtout pas de comprendre ce qu'il fais ;-) La ce que je veux, c'est comprendre, pour pouvoir avancer proprement.
Sinon pour joindre le projet tu zippes le dossier complet et tu le mets comme fichier joint...
bon ben, ça implique qu'il y a mon nom et tout, ok, j'assume!
y'a meme la photo de mon pitou comme test de fond ;-)