web-dev-qa-db-fra.com

Storyboard - reportez-vous à ViewController dans AppDelegate

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 de ce ViewController au projet et spécifie le nom de la nouvelle classe dans l'inspecteur d'identité d'IB. Maintenant, comment vais-je faire référence à ce ViewController par programme à partir de AppDelegate? J'ai créé une variable avec la classe appropriée et l'ai convertie en propriété IBOutlet, mais je ne vois aucun moyen de faire référence au nouveau ViewController dans le code. Toute tentative de glisser-déposer d'une connexion ne fonctionne pas. .

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

(MyViewController*) self.window.rootViewController

mais qu'en est-il des autres ViewController contenus dans le storyboard?

121
Matthias D

Regardez la documentation pour -[UIStoryboard instantiateViewControllerWithIdentifier:]. Cela vous permet d'instancier un contrôleur de vue à partir de votre scénario en utilisant l'identifiant que vous avez défini dans l'inspecteur d'attributs IB:

enter image description here

EDITED pour ajouter un exemple de code:

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

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];
165
Robin Summerhill

Si vous utilisez XCode 5, vous devriez le faire différemment.

  • Sélectionnez votre UIViewController dans UIStoryboard
  • Allez au Identity Inspector dans le volet supérieur droit
  • Vérifier la Use Storyboard ID case à cocher
  • Ecrivez un identifiant unique au Storyboard ID champ

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;
41
Faruk Toptas

Généralement, 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 de viewController en saisissant une référence à la self.window.rootViewController _ par opposition à l’initialisation des contrôleurs de vue, qui devraient déjà être initialisés correctement si vous avez correctement configuré votre storyboard.

Donc, supposons que votre rootViewController soit un UINavigationController et que vous souhaitiez ensuite envoyer quelque chose à son contrôleur de vue supérieure, vous le feriez comme cela dans votre didFinishLaunchingWithOptions de votre AppDelegate:

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

Dans Swift si 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 à l'aide des identifiants de storyboard du délégué de l'application, à moins de vouloir contourner la manière normale de charger le storyboard et de charger vous-même tout le storyboard. Si vous devez initialiser des scènes à partir d'AppDelegate, vous ferez probablement quelque chose de mal. Je veux dire, imaginons que vous vouliez, pour une raison quelconque, envoyer des données à un contrôleur de vue de manière très distante, l'AppDelegate ne devrait pas atteindre la pile de contrôleur de vue pour définir des données. Ce n'est pas son affaire. Son métier est le rootViewController. Laissez le rootViewController gérer ses propres enfants! Donc, si je contournais le processus normal de chargement du storyboard par le système en supprimant les références à celui-ci dans le fichier info.plist, au mieux, instancierait rootViewController à l'aide de instantiateViewControllerWithIdentifier:, 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 déjà instanciés par le storyboard. C'est un problème que je vois beaucoup. En bref, je suis en désaccord avec la réponse acceptée. C'est incorrect à moins que les affiches ne suppriment le chargement du storyboard de l'info.plist car 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 vous l'avez ensuite réinstallée et réaffectée. Votre application a pris un très mauvais départ!

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