Passer un tableau à  un autre controleur via un segue

Hello,


 


j'essaie en vain de passer un tableau un autre controleur.


Dans le contrôleur source, je fais ceci:



[self performSegueWithIdentifier:@controler2 sender:self];

et



- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

DestinationViewController *destController = segue.destinationViewController;

if (destController.view) {

NSArray *myTab = [[NSArray alloc] initWithObjects:@1, @2, @3, @4, nil];
destController.tab = myTab;
}
}

Dans le contrôleur destination, le tableau (ici, tab) est null. Me suis je mal pris ? Comment passer correctement un tableau à  un autre contrôleur ?


 


merci


Réponses

  • Bonjour,


     


    Es-tu sûr que tu passes bien dans ton if... ? Quel est l'intérêt d'ailleurs de tester l'existence de ta view ?


    Comment est déclarée ta propriété tab dans DestinationViewController ?


  • Axel PeignéAxel Peigné Membre
    octobre 2013 modifié #3

    Je ne suis pas sur à  100% de ma réponse vu que je débute un peu dans le développement iOS, mais il me semble que le problème vient de



    if (destController.view)

    Si je ne me trompe pas, lors du prepareForSegue, la view du contrôleur de destination n'existe pas encore : viewDidLoad n'a pas encore été appelé pour ce contrôleur. Donc quand tu fais ta vérification avec destController.view, la réponse est toujours nil. Je te conseille plutôt de faire une vérification du type (en imaginant que tu as une propriété tab dans ton destController) :



    if ([destController respondsToSelector:@selector(setTab:)]) {
    NSArray *myTab = [[NSArray alloc] initWithObjects:@1, @2, @3, @4, nil];
    [destController performSelector:@selector(setTab:) withObject:myTab];
    }



  •  


    Je ne suis pas sur à  100% de ma réponse vu que je débute un peu dans le développement iOS, mais il me semble que le problème vient de



    if (destController.view)

    Si je ne me trompe pas, lors du prepareForSegue, la view du contrôleur de destination n'existe pas encore : viewDidLoad n'a pas encore été appelé pour ce contrôleur. Donc quand tu fais ta vérification avec destController.view, la réponse est toujours nil. Je te conseille plutôt de faire une vérification du type (en imaginant que tu as une propriété tab dans ton destController) :




     


    À ce stade, la view existe bel et bien si elle associée au storyboard. Le viewDidLoad n'est certes pas encore appelé mais le awakeFromNib: si.



  • À ce stade, la view existe bel et bien si elle associée au storyboard. Le viewDidLoad n'est certes pas encore appelé mais le awakeFromNib: si.




     


    Ah d'accord, mais dans ce cas c'est surprenant que le if retourne nil non ?

  • destController est peut-être lui même à  nil. Peut-être que le if ne retourne pas nil... Vu qu'on ne sait pas ce qu'il a vérifié de toute façon... 


  • j'ai utilisé



    if (destController.view)

    car je teste m'avais sauvé la vie dans un projet. sans ce teste toutes les données envoyées au contrôleur destinantion étaient nulles. je n'ai jamais compris pourquoi.





  • if ([destController respondsToSelector:@selector(setTab:)]) {
    NSArray *myTab = [[NSArray alloc] initWithObjects:@1, @2, @3, @4, nil];
    [destController performSelector:@selector(setTab:) withObject:myTab];
    }




    [destController respondsToSelector:@selector(setTab:)]

    renvoie [tt]un ? inversé[/tt]


    mais le code suivant fonctionne bien



    [destController performSelector:@selector(setTab:) withObject:myTab];

    je l'utilise à  la place de ce code



    destController.tab = myTab;
  • Visiblement ça ne résoud pas ton problème puisque même avec ce test tes valeurs sont nul (c'est l'objet même de ta question).


     


    Tu dois avoir quelque chose de mal construit quelque part.

  • AliGatorAliGator Membre, Modérateur

    j'ai utilisé


    if (destController.view)
    car je teste m'avais sauvé la vie dans un projet. sans ce teste toutes les données envoyées au contrôleur destinantion étaient nulles. je n'ai jamais compris pourquoi.

    Il serait sans doute intéressant de se pencher sur le problème et comprendre pourquoi.
    Trouver une bidouille qui permet de "faire tomber en marche" ton code sans comprendre par quelle magie, ce n'est jamais bon, et souvent ça sous-entend que ce n'est pas la bonne solution mais plutôt un coup de bol que ça marche dans ton cas. Il vaut toujours mieux comprendre le problème puis le résoudre, plutôt que de bidouiller dans tous les sens sans savoir ce qu'on fait pour tenter de trouver un truc qui marche comme par magie sans qu'on comprenne pourquoi... car cela va te mener à  des cas comme celui dans lequel tu es aujourd'hui, à  retomber dans un cas qui foire en comprenant encore moins ce qui arrive.
     
     


    [destController respondsToSelector:@selector(setTab:)]
    renvoie [tt]un ? inversé[/tt]

    Heu ça ne peut pas être le cas. C'est un booléen, ça retourne YES ou NO, 1 ou 0, mais pas "¿". Si tu vois ça, je suis curieux de savoir comment tu as inspecté ladite valeur retournée. Forcément si tu as utilisé la commande "po" dans ta console Xcode pour afficher le résultat de cette ligne, oui c'est normal qu'il t'affiche un truc bizarre comme "¿". Mais ce n'est pas du tout la valeur de la variable. Si tu mets le résultat de ton "[destController respondsToSelector:@selector(setTab:)]" dans une variable de type BOOL (puisque c'est le type de retour de cette méthode), tu verras que ça ne peut pas valoir "¿" mais que YES ou NO. Si tu vois "¿" c'est que tu fais une mauvaise interprétation du résultat, pas que le résultat est incorrect. Un peu comme si tu faisais un "NSLog(@x=%d,x)" mais que x était une NSString et pas du tout un entier... forcément si tu lui demandes de l'interpréter comme ce qu'il n'est pas (dans le cas de "po", un objet ObjC au lieu d'un BOOL) forcément c'est comme essayer de déchiffrer de l'allemand à  un traducteur norvégien->français...



    Et sinon pour répondre à  vos questions, non tant que le viewDidLoad n'est pas appelé, la vue n'est pas chargée (c'est un peu normal, viewDidLoad est appelé JUSTEMENT pour signaler qu'il a chargé la vue qui n'était pas chargée avant). C'est le principe du lazy-loading (qui fait d'ailleurs tout l'intérêt des UIViewControllers). Un UIViewController ne charge pas sa vue tant qu'il n'en a pas besoin ou qu'on n'accède pas à  sa propriété "view".

    Justement pour ton cas magique que tu ne comprenais pas dont on parle plus haut, le fait de rajouter "destController.view" fait que tu demandes d'accéder à  la propriété "view" du UIViewController. Comme à  ce moment-là  la vue n'est pas chargée (et c'est tant mieux, elle n'a pas à  l'être dans le prepareForSegue, c'est une optimisation mémoire qui est pensée exprès de la part d'Apple et c'est logique), le fait d'accéder à  la propriété "view" va forcer le UIViewController à  la charger. Et donc à  appeler viewDidLoad dans la foulée, logique. Ton ajout de "if (destController.view)" ne fait donc pas vraiment ce que tu crois faire, il teste si la vue est nil, certes, mais il a surtout le side-effect important... de forcer à  charger la vue (et à  ce que le viewDidLoad soit appelé). Tu le mettrais en dehors d'un if en mettant juste "(void)destController.view" pour forcer à  charger la vue ça marcherait tout pareil, avec ou sans "if".

    Et c'est une très mauvaise solution. Il faut éviter de forcer à  charger la vue, si elle n'est pas encore chargée à  ce moment là  c'est qu'il y a une raison, en particulier pour éviter de charger toute la vue et tout son XIB (ou toute sa scène storyboard) et instancier toute la hiérarchie de vue tant que ce n'est pas strictement nécessaire (= pour l'affichage). Ca évite les pics mémoire et consommation de RAM inutiles, ce qui est important sur un device mobile.
    Ton problème vient plutôt du fait que tu ne dois pas mettre ton code qui utilise le tableau au bon endroit dans la bonne méthode, tu as par exemple peut-être remis à  nil ton tableau dans le viewDidLoad de ton UIViewController, ce qui expliquerait pourquoi si tu forces à  loader la view avant au début de ton prepareForSegue, ça reset le tableau, puis tu l'affectes, alors que si tu codes comme c'est prévu et ne forces pas la vue à  se charger ça affecte le tableau puis le remet à  nil plus tard quand la vue sera chargé. Alors que le reset il aurait fallu le mettre dans le init de ton UIViewController.

    Fais bien attention à  respecter ce pour quoi les méthodes sont faites. Mettre du code dans le viewDidLoad alors qu'il doit être mis dans le init c'est sans doute parce que tu n'as pas encore bien assimilé la logique de fonctionnement du chargement d'un UIViewController, le process et l'ordre des étapes qui sont faites (un tour dans le View Controller Programming Guide devrait grandement aider à  combler ce manque). N'hésite pas à  mettre des breakpoints dans les méthodes genre init, viewDidLoad, viewWillAppear, viewDidAppear, ton prepareForSegue, etc... pour comprendre dans quel ordre ces méthodes sont appelée. Et vire moi tout de suite ce if(destController.view) qui casse toute la logique de lazy-loading qu'apportent les UIViewControllers.
  • merci [twitter]AliGator[/twitter]





  • Justement pour ton cas magique que tu ne comprenais pas dont on parle plus haut, le fait de rajouter "destController.view" fait que tu demandes d'accéder à  la propriété "view" du UIViewController. Comme à  ce moment-là  la vue n'est pas chargée (et c'est tant mieux, elle n'a pas à  l'être dans le prepareForSegue, c'est une optimisation mémoire qui est pensée exprès de la part d'Apple et c'est logique), le fait d'accéder à  la propriété "view" va forcer le UIViewController à  la charger. 




     


    Ah tiens, je pensais que la vue d'un controller était forcément chargée... comme quoi...

  • AliGatorAliGator Membre, Modérateur
    Bah non c'est d'ailleurs entre autres pour ça qu'il y a une méthode viewDidLoad, sinon ça serait la même chose que "-init" ! (Et pourquoi y' aurait une méthode "isViewLoaded" sinon aussi ? ^^)


    Tu peux instancier un UIViewController et qu'il n'instancie jamais sa vue s'il n'en a pas besoin (si tu ne l'affiches jamais par exemple), ce qui évite de désarchiver le XIB ou la scène du Storyboard et créer toute la hiérarchie de vue et instancier toutes les subviews que tu as dans le XIB pour rien !
  • Merci pour toutes les explications AliGator !




  • Bah non c'est d'ailleurs entre autres pour ça qu'il y a une méthode viewDidLoad, sinon ça serait la même chose que "-init" ! (Et pourquoi y' aurait une méthode "isViewLoaded" sinon aussi ? ^^)


    Tu peux instancier un UIViewController et qu'il n'instancie jamais sa vue s'il n'en a pas besoin (si tu ne l'affiches jamais par exemple), ce qui évite de désarchiver le XIB ou la scène du Storyboard et créer toute la hiérarchie de vue et instancier toutes les subviews que tu as dans le XIB pour rien !




     


    Oui, évidemment, tout ça se tient  8--) Merci.

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