Storyboard - reportez-vous à ViewController dans AppDelegate

122

considérez le scénario suivant: J'ai une application basée sur un storyboard. J'ajoute un objet ViewController au storyboard, ajoute les fichiers de classe pour ce ViewController dans le projet et spécifie le nom de la nouvelle classe dans l'inspecteur d'identité IB. Maintenant, comment vais-je faire référence à ce ViewController par programmation à partir de AppDelegate? J'ai créé une variable avec la classe appropriée et l'ai transformée en propriété IBOutlet, mais je ne vois aucun moyen de faire référence au nouveau ViewController dans le code - toute tentative de ctrl-glisser une connexion ne fonctionne pas .

c'est-à-dire que dans l'AppDelegate, je peux accéder au ViewController de base comme ceci

(MyViewController*) self.window.rootViewController

mais qu'en est-il de tout autre ViewController contenu dans le storyboard?

Matthias D
la source
Vérifiez cette réponse . C'est rapide, mais les langues sont similaires.
Borzh

Réponses:

165

Jetez un œil à la documentation de -[UIStoryboard instantiateViewControllerWithIdentifier:]. Cela vous permet d'instancier un contrôleur de vue à partir de votre storyboard à l'aide de l'identifiant que vous avez défini dans l'inspecteur d'attributs IB:

entrez la description de l'image ici

EDITED pour ajouter un exemple de code:

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                         bundle: nil];

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];
Robin Summerhill
la source
Salut Robin, merci pour ça! J'ai regardé ce document mais j'ai mélangé les mots instanciation et initialisation ... cela nous y conduit (après avoir suivi vos instructions :) (putain le manque de formatage du code dans les réponses ...) UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName: @ Bundle "MainStoryboard": néant]; MyViewController * thisController = (MyViewController *) [mainStoryboard instantiateViewControllerWithIdentifier: @ "myvc"];
Matthias D
J'ai ajouté votre exemple de code à la réponse avec la mise en forme pour quiconque regarde cela.
Robin Summerhill
24
si vous créez une application universelle, assurez-vous d'utiliser MainStoryboard_iPhone / MainStoryboard_iPad, sinon vous aurez un plantage.
roocell
16
Depuis le délégué, vous pouvez accéder à l'instance de storyboard chargée par votre info.plist comme ceci: [[[self window] rootViewController] storyboard] selon la documentation, cela retournera le "storyboard à partir duquel le contrôleur de vue est issu." (ou nul s'il ne provient pas d'un storyboard). À partir de cet UIStoryboard *, vous pouvez utiliser les appels d'instanciation mentionnés par @RobinSummerhill. Notez que les storyboards instancient de nouvelles instances de vos viewControllers ( scènes ) au fur et à mesure qu'elles sont nécessaires et ne réutilise pas celles qui ont été précédemment visualisées.
Tad Bumcrot
6
Je crois que l'OP veut savoir COMMENT SE RENDRE AU VC ACTUELLEMENT EN COURS. Pas comment en charger un. Exactement comme il l'explique, vous pouviez dire ce self.window.rootViewController et maintenant vous ne pouvez plus.
Fattie
41

Si vous utilisez XCode5, vous devez le faire d'une manière différente.

  • Sélectionnez votre UIViewControllerdansUIStoryboard
  • Accédez au Identity Inspectorvolet supérieur droit
  • Cochez la Use Storyboard IDcase
  • Écrivez un identifiant unique dans le Storyboard IDchamp

Ensuite, écrivez votre code.

// Override point for customization after application launch.

if (<your implementation>) {
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" 
                                                             bundle: nil];
    YourViewController *yourController = (YourViewController *)[mainStoryboard 
      instantiateViewControllerWithIdentifier:@"YourViewControllerID"];
    self.window.rootViewController = yourController;
}

return YES;
Faruk Toptas
la source
4
Pour autant que je sais et ai pu l' essayer, c'est la réponse mise à jour.
gnclmorais
Le nom d'un storyboard est son nom de fichier sans l'extension, il peut donc également être "Main_iPhone" ou "Main_iPad" si vous avez configuré votre projet de cette façon.
Brian White
puis comment revenir au rootViewController d'origine après la connexion. Au moins à ma connaissance d'iOS 7 et de Xcode 5.0.2 - la modification du contrôleur de vue racine reviendra immédiatement et sans animation changera la hiérarchie des vues. L'équipe UX a assassiné des codeurs pour moins cher.
lol
Comment pourrais-je faire cela en utilisant Swift?
Leo Dabus
8

En règle générale, le système doit gérer l'instanciation du contrôleur de vue avec un storyboard. Ce que vous voulez, c'est parcourir la hiérarchie viewController en saisissant une référence aux self.window.rootViewControllercontrôleurs de vue par opposition à l'initialisation, qui devrait déjà être initialisé correctement si vous avez correctement configuré votre storyboard.

Donc, disons que vous rootViewControllerêtes un UINavigationController et que vous voulez envoyer quelque chose à son contrôleur de vue de dessus, vous le feriez comme ceci dans votre AppDelegate didFinishLaunchingWithOptions:

UINavigationController *nav = (UINavigationController *) self.window.rootViewController;
MyViewController *myVC = (MyViewController *)nav.topViewController;
myVC.data = self.data;

Dans Swift, ce serait très similaire:

let nav = self.window.rootViewController as! UINavigationController;
let myVC = nav.topViewController as! MyViewController
myVc.data = self.data

Vous ne devriez vraiment pas initialiser les contrôleurs de vue en utilisant les identifiants de storyboard du délégué de l'application, sauf si vous souhaitez contourner la façon normale de charger le storyboard et de charger vous-même l'ensemble du storyboard. Si vous devez initialiser des scènes depuis AppDelegate, vous faites probablement quelque chose de mal. Je veux dire, imaginez que vous, pour une raison quelconque, souhaitez envoyer des données à un contrôleur de vue en bas de la pile, l'AppDelegate ne devrait pas atteindre la pile de contrôleurs de vue pour définir les données. Ce n'est pas son affaire. C'est le business est le rootViewController. Laissez rootViewController gérer ses propres enfants! Donc, si je contournais le processus de chargement normal du storyboard par le système en supprimant les références à celui-ci dans le fichier info.plist, je voudrais au plus instancier le rootViewController en utilisantinstantiateViewControllerWithIdentifier:, et éventuellement sa racine s'il s'agit d'un conteneur, comme un UINavigationController. Ce que vous voulez éviter, c'est d'instancier des contrôleurs de vue qui ont déjà été instanciés par le storyboard. C'est un problème que je vois souvent. En bref, je ne suis pas d'accord avec la réponse acceptée. C'est incorrect à moins que les affiches ne signifient de supprimer le chargement du storyboard de info.plist puisque vous aurez chargé 2 storyboards autrement, ce qui n'a aucun sens. Ce n'est probablement pas une fuite de mémoire car le système a initialisé la scène racine et l'a assignée à la fenêtre, mais ensuite vous êtes venu et vous l'avez instanciée à nouveau et l'avez affectée à nouveau. Votre application a bien mal démarré!

smileBot
la source
0
    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];
Ofir Malachie
la source