Passer un objet d'une vue a une autre
Hello,
je bloque dans le passage de donnée d'une vue à une autre.
J'ai longtemps cherché sur le net, et j'ai notamment trouvé "PrepareForSegue" afin de passer des données. Si j'ai bien compris, "prepareForSegue" permet de passer des données d'une vue à une autre (d'une vue A en push a une vue B par exemple).
Mon problème étant que je souhaiterai faire passer des données de la vue B à la vue A.
Plus précisément, les 2 vues sont relié en Push (avec un Navigation Controller), je souhaiterai de ce fait envoyer des données dès que le bouton de retour de la vue B est pressé. Chose qui doit etre relativement simple, mais je n'ai pas réussie à trouvé la réponse sur le net...
De façon plus simple, mon interface :
- appuyer sur une cellule de A qui envoie sur B en push, lui meme composé d'un tableView
L'utilisateur "coche" un element du tableau, et lorsque il appuie sur retour afin de revenir sur A, les données de la cellule concerné de 1 doivent êtres modifiés.
Autre question, mes deux vues sont de la meme classe, est ce un soucis ? Doit on avoir une classe par CV ?
Merci de votre aide !
Réponses
Bonjour,
alors je vais tenter de te répondre car je suis aussi passé par là , j'en ai chié et j'aurais bien aimé trouvé une réponse comme ça. Ta question est assez simple ce qui explique qu'il n'y ait pas foule pour te répondre, et en même temps c'est assez difficile d'être clair. Je vais donc essayer.
La méthode prepareForSegue est effectivement la bonne. Mais il y a plusieurs choses à faire avant de l'utiliser. Tu parles de tableView, as-tu bien implémenter le délégué ? ensuite l'idéal pour passer des données est de créer un protocole dans la classe de ton deuxième tableView. Enfin Dans myFirstViewController il faut instancier un objet UIStoryboardPopoverSegue *currentpopoverSegue;
Dans storyBoard tu donnes un nom à ton segue en cliquant dessus et en configurant tout cela dans le volet utilitaire de droite puis tu peux utiliser prepareForSegue en spécifiant le nom de ton segue si tu en as plusieurs, sinon il fera la même action quelque soit le segue.
Selon moi tu dois avoir une classe pour chaque vue, mais peut-être que des plus expérimentées infirmerons cela. Niveau code je peux te proposer cela :
firstTableViewController.h
firstTableViewController.m
dans SecondViewController.h :
Enfin dans SecondViewController.m : tranquillou tu remets les méthodes obligatoires pour créer ton tableView, et à la fin la méthode magique qui va repasser les infos de la vue B vers la vue A :
En espérant avoir été clair et que ça aide.
Cordialement.
[edit correction d'étourderies]
Bonjour,
Merci pour cette super explication ! Cela fonctionne a merveille, et grâce tes nombreux commentaires je pense avoir compris le principe.
Un petit soucis persiste cependant, j'obtient un warning lorsque je fais :
secondViewController.tableDelegue = self;
Il s'agit visiblement d'un problème de typage : "Assigning to 'id<TableDelegate>' from incompatible type 'nomDuPremierController *const_strong'
C'est en effet la première fois que j'utilise une syntaxe tel que "id<TableDelegate>", je suis un peu perdu une nouvelle fois !
Une idée ?
(sinon tout fonctionne parfaitement, mais me trimbaler un warning n'est jamais bon, d'autant plus lorsqu'on ne comprend pas l'erreur...)
Un peu de lecture et plus précisément ici ?
À la base, si ta variable est typée avec un protocole <TonProtocole> taVariable alors tu dois avoir ce même protocole déclaré dans l'interface de la classe de taVariable.
Un protocole sert à déclarer qu'un objet possédera certaines méthodes. D'aucunes optionnelles, d'autres obligatoires.
Si ta variable est déclarée comme respectant ce protocole sa classe doit l'avoir déclaré aussi dans son interface. Sinon ça passe avec un warning et ça fonctionne tant que la méthode appelée est présente..
Je n'aurais pas dis mieux, en tout cas je n'aurais pas retrouvé la doc. ^^
Dans FirstViewController. je t'ai mis une ligne :
"tes délégués" fait référence à tous les délégués auxquels ta classe doit se conformer et répondre. Donc tous les objets qui nécessitent un délégué (UITextField, UIScrollView, UIPicker...) doivent spécifier à la classe de faire attention aux actions qu'ils permettent. C'est justement sur cette ligne @interface que tu spécifies les protocoles qui intègrent les méthodes obligatoires et optionnelles relatives aux délégués. Si j'ai bien compris tu as un tableView dans ta vue, de plus tu aimerais que ta classe se conforme à ton custom protocole, donc il faut le spécifier :
J'ai fais exprès de l'appeler TableDelegue et non TableDelegate car au début c'était assez flou pour moi et je trouvais que ça ressemblait trop à UITableViewDelegate, mais bien sûr le nom est libre.
En espérant que ça aide.
Bon courage.
Merci pour ces réponses, tout est plus clair maintenant. Et oui effectivement je devrais me reporter plus souvent à la doc... Et surtout améliorer mon anglais :P
J'ai le même problème, mais je n'ai pas de storyboard, j'essaie de tout faire en mode programmatique.
Voici mon souci.
J'essaie de créer une application basée sur un tabbarcontroller qui gère deux view contrôler : un pour créer un tableau d'épingles ("stepCollection") sur une mapview, l'autre pour faire apparaà®tre au fur et à mesure ces épingles via le tableau que j'ai crée dans le premier que j'aimerais faire pointer par mon objet "stepCollectionP"v. Mes épingles sont des instances d'une classe que j'ai crée (comme les étapes d'une chasse au trésor) et sont collectées dans un objet défini par une classe qui l'englobe.
Mon problème est que je n'arrive pas à mettre mon objet stepCollection dans mon autre objet stepCollectionP.
Auriez vous une idée?
Merci de votre aide.
Mickael
Alors il me semble qu'il y a plusieurs solution la première est de récupérer ton second viewController via ta tabBar un genre de [self.tabBarController controllerAtIndex:1] c'est pas la ligne de code exacte mais ça devrait ressembler à ça.
Ensuite tu pourrais notifier le changement via le notification center en passant ton objet.
Sinon tu peux enregistrer ton objet en local dans le device et le recuperer quand tu arrives sur ton second viewController
Tu peux éventuellement faire un délégué bien que je trouve pas ça très classe avec un tabBarController il faudrait déclarer tout ça dans le delegate je sais pas ça marcherait potentiellement mais je trouve pas ça super beau.
En fait la difficulté de ton problème par rapport à celui d'avant c'est que pour le problème du dessus A déclare B et le pousse ils sont en quelques sorte lié mais pour toi A et B sont créé en même temps et sont contenu en parallèle dans la tabBar. Du coup tu profitera pas du cycle de vie (init -> viewWillAppear -> ....) donc il faut recharger les données en temps réel. Pour moi la notification tient la route dans ce cas la. Je sais pas si c'est la meilleurs solution ceci dit.
Merci bcp je vais tenter ta solution sur les notifications.
J'ai essayé d'implémenter dans mon appdelegate dès que je choisis mon deuxième tabBar (didSelectViewController) :
if (viewController==tvc) {
[tvc gameView] stepCollectionP] setStepCollectionObject:[[tbc creationView] stepCollection;
};
Rien n'y fait. Je suis perplexe. Mon stepCollectionP dans mon tbc(2° view controller de mon tabBar) est toujours à nil.
J'ai une démarche alternative qui peut vous intéresser.
En utilisant le blocks on peut simplifier le code un peu. J'ai mis un projet téléchargeable sur mon site à http://carterconsulting.org.uk/Examples/TransmissionDeDonn%C3%A9es.zip
Ici, se trouve l'essentiel...
Merci pour toute cette aide.
J'ai bien peur d'être obligé d'ajouter un navigation contrôler au final. Tous les exemples que je trouve en ont un.
Mais pourquoi ? C'est un parcours assez lourd !
Parce que c'est la bonne route. Sinon, c'est beaucoup plus de travaille pour réaliser le même but
Je viens de voir que tu utilises un tab bar controller, du coup, voir mon prochain message
Est-ce que tu as un modèle que les deux view controllers puissent voir au même temps ?
Si oui, est-ce que tu lis les données de cet modèle, dans les view controllers, pour actualiser les deux vues ?
Donc, il faut créer une notification qui est provoqué pendant la méthode qui reçoit le message de change dans n'importe quelle view controller.
Puis, ce notification s'accroche dans les deux view controllers, afin que tu puisses mettre à jour la vue.
ça c'est le MVC (Modèle Vue Contrôleur) :-*
Mon modèle est constitué d'une classe représentant les étapes de la chasse au trésor et d'une autre classe qui est en fait un MutableArray de ces étapes (stepCollection).
Mon premier controller gère une instance stepCollection pour stocker les différentes étapes que je crée via la vue (MapView) géré par ce controller.
Le deuxième controller déclare dans sa vue une autre instance (stepCollectionP). Est-ce que je devrais tout déclare dans le AppDelegate pour avoir une seule instance accessible par les deux controller?
Ca ne me semble pas être la bonne solution car cela revient à avoir une instance globale non?
Pas de soucis ;-)
Si tu déclarais une instance comme un @property dans le AppDelegate, elle ne serait pas globale, elle serait membre de la classe. Rien ne t'empêche de passer une référence de cette instance aux deux controllers.
Est-il autorise d'accéder à l'appdelegate dans les sous vues?
Si tu veux faire simple pour l'instant :
Le UITabController contient la liste des contrôleurs qui sont actuellement affichés dans un array. Donc tu récupère celui qui t'intéresse avec l'index. L'index 0 correspond au contrôleurs le plus à gauche ( le premier) et ainsi de suite.
un truc de genre :
Il n'est pas interdit d'accéder l'AppDelegate mis il est fortement déconseillé
Comment crées-tu les view controllers et les ajoutes au tab controller ? En code ou depuis un storyboard ?
C'est pour ça que je posais la question car le principe me semblait violent et ne me plaisait pas.
Je crée tout en programmatique sur les conseils d'un MOOC que j'ai suivi (plateforme FUN, MOOC de l'UPMC)...Au final, quand je fais des recherches sur internet, je vois tellement d'utilisation de storyboard qui a l'air tellement plus sympa en plus! bref, je crée les les viewcontroller dans le appdelegate, les insère dans un tableau que j'assigne à viewcontrollers du tabBarcontroller. Ensuite, j'ai un viewcontroller pour mes deux ongles qui contiennet chacun une vue différente définie aussi en code.
::)
Ouahouh ! Un MOOC qui n'enseigne pas les storyboards ? C'est du Moyen à‚ge !
Les storyboards, ou même les XIB sont beaucoup plus efficaces et, surtout, plus faciles.
Je ne peux pas démontrer comment faire le storyboard ici, mais voici quelques extraits de code que l'on puisse utiliser avec un storyboard...
Si tu voulais, je pourrait t'envoyer le projet basique complet.
Si tu préfères rester en code, voici l'AppDelegate presque pareil...
Pour avoir suivi ce MOOC également puis abandonné vers la fin, c'est clair que la ligne pédagogique est préhistorique. J'ai fait remonter ça dans le questionnaire et autres, mais le ton de l'équipe pédagogique concernant ARC et storyboard est ultra pédant et conservateur, ceux qui l'ont suivi comprendront bien.
*/
Je suis assez d'accord avec toi Mayerick. J'ai fait tous les exercices sauf le dernier en utilisant ARC car si Apple a implémenté ce concept ce n'est pas pour rien.
Storyboard est en plus un outil assez sympa et les cours du Big Nerd Ranch ou de Stanford s'appuient dessus, selon moi gage de sérieux...
Bref, concernant les vues, l'aspect programmatique était assez bien pour comprendre comment cela marchait (mon expérience est assez réduite j'ai débuté l'objective-c il y a 4 mois) mais du coup cela me prive de fonctionnalités pourtant intéressante.
Merci Joanna pour ton exemple, je regarde ça de suite.
Pour autant, je n'arrive pas a passer mon objet à ma deuxième vue. Son objet stepcollection reste à nil malgre ma ligne de code pour lui transmettre les mêmes infos que l'objet de la première vue. Quelqu'un aurait une idée?
Mais pourquoi ? Tu as commencé en créant un app tab bar dont il n'y a aucune nécessité d'ajouter un navigation controller pour accomplir ce que tu voulais.
Est-ce que tu peux nous afficher le code, que tu as fait, qui crée les deux controllers ?