Storyboard: fare riferimento a ViewController in AppDelegate


122

considera il seguente scenario: ho un'app basata su storyboard. Aggiungo un oggetto ViewController allo storyboard, aggiungo i file di classe per questo ViewController nel progetto e indico il nome della nuova classe nell'ispettore di identità IB. Ora come faccio a fare riferimento a questo ViewController a livello di codice da AppDelegate? Ho creato una variabile con la classe pertinente e l'ho trasformata in una proprietà IBOutlet, ma non vedo alcun modo per poter fare riferimento al nuovo ViewController nel codice: qualsiasi tentativo di ctrl-trascinare una connessione non funziona .

cioè all'interno di AppDelegate posso arrivare al ViewController di base in questo modo

(MyViewController*) self.window.rootViewController

ma che ne dici di qualsiasi altro ViewController contenuto nello storyboard?


Controlla questa risposta . È veloce, ma le lingue sono simili.
Borzh

Risposte:


165

Dai un'occhiata alla documentazione per -[UIStoryboard instantiateViewControllerWithIdentifier:]. Ciò consente di creare un'istanza di un controller di visualizzazione dallo storyboard utilizzando l'identificatore impostato in IB Attributes Inspector:

inserisci qui la descrizione dell'immagine

MODIFICATO per aggiungere codice di esempio:

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

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

Ciao Robin, grazie per questo! Ho guardato questo documento ma ho confuso le parole istanza e inizializzazione ... questo ci porta lì (dopo aver seguito le tue istruzioni :) (accidenti alla mancanza di formattazione del codice nelle risposte ...) UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName: @ Pacchetto "MainStoryboard": nil]; MyViewController * thisController = (MyViewController *) [mainStoryboard instantiateViewControllerWithIdentifier: @ "myvc"];
Matthias D

Ho aggiunto il tuo codice di esempio alla risposta con la formattazione per chiunque stia guardando questo.
Robin Summerhill

24
se stai creando un'app universale assicurati di utilizzare MainStoryboard_iPhone / MainStoryboard_iPad altrimenti otterrai un arresto anomalo.
roocell

16
Dall'interno del delegato puoi accedere all'istanza dello storyboard caricata dal tuo info.plist in questo modo: [[[self window] rootViewController] storyboard] Secondo i documenti, questo restituirà lo "storyboard da cui ha avuto origine il controller di visualizzazione". (o nullo se non proveniva da uno storyboard). Da quella UIStoryboard * puoi utilizzare le chiamate di istanza menzionate da @RobinSummerhill. Nota che gli storyboard creano nuove istanze dei tuoi viewController ( scene ) quando sono necessari e non riutilizzano quelli che sono stati visualizzati in precedenza.
Tad Bumcrot

6
Credo che l'OP voglia sapere COME ARRIVARE AL VC ATTUALMENTE IN FUNZIONE. Non come caricarne uno. Esattamente come spiega, eri in grado di dire questo self.window.rootViewController e ora non puoi più.
Fattie

41

Se usi XCode5 dovresti farlo in un modo diverso.

  • Seleziona il tuo UIViewControllerinUIStoryboard
  • Vai al Identity Inspectorriquadro in alto a destra
  • Seleziona la Use Storyboard IDcasella di controllo
  • Scrivi un ID univoco nel Storyboard IDcampo

Quindi scrivi il tuo codice.

// 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;

4
Per quanto ne so e ho potuto provarlo, questa è la risposta aggiornata.
gnclmorais

Il nome di uno storyboard è il nome del file senza l'estensione, quindi potrebbe anche essere "Main_iPhone" o "Main_iPad" se hai impostato il tuo progetto in questo modo.
Brian White

e poi come si torna al rootViewController originale dopo il login. Almeno per la mia conoscenza di iOS 7 e Xcode 5.0.2, la modifica del controller della vista di root sarà immediata e senza animazione cambierà la gerarchia della vista. Il team UX ha ucciso programmatori per meno.
lol

Come lo farei usando Swift?
Leo Dabus

8

In generale, il sistema dovrebbe gestire la creazione di istanze del controller di visualizzazione con uno storyboard. Quello che vuoi è attraversare la gerarchia di viewController afferrando un riferimento al self.window.rootViewControllerinvece di inizializzare i controller di visualizzazione, che dovrebbero già essere inizializzati correttamente se hai impostato correttamente lo storyboard.

Quindi, diciamo che il tuo rootViewControllerè un UINavigationController e quindi vuoi inviare qualcosa al suo controller di visualizzazione superiore, lo faresti in questo modo nel tuo AppDelegate didFinishLaunchingWithOptions:

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

In Swift se sarebbe molto simile:

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

Non dovresti davvero inizializzare i controller di visualizzazione utilizzando gli ID dello storyboard dal delegato dell'app a meno che tu non voglia aggirare il normale modo in cui lo storyboard viene caricato e caricare l'intero storyboard da solo. Se devi inizializzare scene da AppDelegate, molto probabilmente stai facendo qualcosa di sbagliato. Voglio dire, immagina che tu, per qualche motivo, desideri inviare dati a un controller di visualizzazione in fondo allo stack, AppDelegate non dovrebbe raggiungere lo stack del controller di visualizzazione per impostare i dati. Non sono affari suoi. Il suo business è rootViewController. Lascia che rootViewController gestisca i propri figli! Quindi, se ignorassi il normale processo di caricamento dello storyboard da parte del sistema rimuovendo i riferimenti ad esso nel file info.plist, al massimo istanzerei il rootViewController usandoinstantiateViewControllerWithIdentifier:e possibilmente la sua radice se è un contenitore, come un UINavigationController. Quello che vuoi evitare è creare un'istanza dei controller di visualizzazione che sono già stati istanziati dallo storyboard. Questo è un problema che vedo spesso. In breve, non sono d'accordo con la risposta accettata. Non è corretto a meno che i poster non intendono rimuovere il caricamento dello storyboard da info.plist poiché altrimenti avresti caricato 2 storyboard, il che non ha senso. Probabilmente non è una perdita di memoria perché il sistema ha inizializzato la scena radice e l'ha assegnata alla finestra, ma poi sei arrivato tu e l'hai istanziata di nuovo e assegnata di nuovo. La tua app è iniziata piuttosto male!


0
    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.