Storyboard - siehe ViewController in AppDelegate

122

Stellen Sie sich das folgende Szenario vor: Ich habe eine Storyboard-basierte App. Ich füge dem Storyboard ein ViewController-Objekt hinzu, füge die Klassendateien für diesen ViewController zum Projekt hinzu und gebe den Namen der neuen Klasse im IB-Identitätsinspektor an. Wie werde ich nun programmgesteuert aus dem AppDelegate auf diesen ViewController verweisen? Ich habe eine Variable mit der entsprechenden Klasse erstellt und in eine IBOutlet-Eigenschaft umgewandelt, sehe jedoch keine Möglichkeit, im Code auf den neuen ViewController zu verweisen. Jeder Versuch, eine Verbindung bei gedrückter Strg-Taste zu ziehen, funktioniert nicht .

dh innerhalb des AppDelegate kann ich so zum Basis-ViewController gelangen

(MyViewController*) self.window.rootViewController

Aber wie wäre es mit einem anderen ViewController im Storyboard?

Matthias D.
quelle
Überprüfen Sie diese Antwort . Es ist schnell, aber die Sprachen sind ähnlich.
Borzh

Antworten:

165

Schauen Sie sich die Dokumentation für an -[UIStoryboard instantiateViewControllerWithIdentifier:]. Auf diese Weise können Sie einen Ansichtscontroller von Ihrem Storyboard aus mithilfe der im IB-Attributinspektor festgelegten Kennung instanziieren:

Geben Sie hier die Bildbeschreibung ein

BEARBEITET, um Beispielcode hinzuzufügen:

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

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];
Robin Summerhill
quelle
Hallo Robin, danke dafür! Ich habe mir dieses Dokument angesehen, aber die Wörter instanziieren und initialisieren verwechselt ... das bringt uns dorthin (nachdem wir Ihren Anweisungen gefolgt sind :) (verdammt die fehlende Code-Formatierung in den Antworten ...) UIStoryboard * mainStoryboard = [UIStoryboard storyboardWithName: @ "MainStoryboard" -Paket: nil]; MyViewController * thisController = (MyViewController *) [mainStoryboard instantiateViewControllerWithIdentifier: @ "myvc"];
Matthias D
Ich habe Ihren Beispielcode zur Antwort mit Formatierung für jeden hinzugefügt, der sich das ansieht.
Robin Summerhill
24
Wenn Sie eine universelle App erstellen, müssen Sie MainStoryboard_iPhone / MainStoryboard_iPad verwenden, da sonst ein Absturz auftritt.
Roocell
16
Innerhalb des Delegaten können Sie wie folgt auf die von Ihrer info.plist geladene Storyboard-Instanz zugreifen: [[[self window] rootViewController] storyboard] Gemäß den Dokumenten wird das "Storyboard zurückgegeben, von dem der View Controller stammt". (oder null, wenn es nicht aus einem Storyboard stammt). Von diesem UIStoryboard * aus können Sie die von @RobinSummerhill erwähnten Instanziierungsaufrufe verwenden. Beachten Sie, dass Storyboards neue Instanzen Ihrer viewController ( Szenen ) nach Bedarf instanziieren und die zuvor angezeigten nicht wiederverwenden.
Tad Bumcrot
6
Ich glaube, das OP möchte wissen, wie man zum aktuell laufenden VC kommt. Nicht wie man einen lädt. Genau wie er erklärt, konnten Sie diesen self.window.rootViewController sagen und jetzt können Sie nicht mehr.
Fattie
41

Wenn Sie XCode5 verwenden, sollten Sie dies anders machen.

  • Wählen Sie Ihre UIViewControllerinUIStoryboard
  • Gehen Sie zum Identity Inspectorrechten oberen Bereich
  • Aktivieren Sie das Use Storyboard IDKontrollkästchen
  • Schreiben Sie eine eindeutige ID in das Storyboard IDFeld

Dann schreiben Sie Ihren 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
quelle
4
Soweit ich weiß und es ausprobieren konnte, ist dies die aktualisierte Antwort.
Gnclmorais
Der Name eines Storyboards ist sein Dateiname ohne die Erweiterung, daher kann es auch "Main_iPhone" oder "Main_iPad" sein, wenn Sie Ihr Projekt auf diese Weise eingerichtet haben.
Brian White
und wie wechseln wir dann nach der Anmeldung zurück zum ursprünglichen rootViewController. Zumindest nach meinem Wissen über iOS 7 und Xcode 5.0.2 wird durch das Zurücksetzen des Root-View-Controllers sofort und ohne Animation die Ansichtshierarchie geändert. Das UX-Team hat Programmierer für weniger ermordet.
lol
Wie würde ich das mit Swift machen?
Leo Dabus
8

Im Allgemeinen sollte das System die Instanziierung des View Controllers mit einem Storyboard verarbeiten. Sie möchten die viewController-Hierarchie durchlaufen, indem Sie einen Verweis auf die self.window.rootViewControllerView Controller im Gegensatz zur Initialisierung von View Controllern abrufen , die bereits korrekt initialisiert werden sollten, wenn Sie Ihr Storyboard ordnungsgemäß eingerichtet haben.

rootViewControllerNehmen wir also an, Sie sind ein UINavigationController und möchten dann etwas an den Top View Controller senden. Sie würden dies in Ihrem AppDelegate folgendermaßen tun didFinishLaunchingWithOptions:

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

In Swift wäre es sehr ähnlich:

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

Sie sollten View Controller wirklich nicht mit Storyboard-IDs des App-Delegaten initialisieren, es sei denn, Sie möchten die normale Art des Ladens des Storyboards umgehen und das gesamte Storyboard selbst laden. Wenn Sie Szenen aus dem AppDelegate initialisieren müssen, machen Sie höchstwahrscheinlich etwas falsch. Ich meine, stellen Sie sich vor, Sie möchten aus irgendeinem Grund Daten an einen View-Controller weiter unten im Stapel senden. Das AppDelegate sollte nicht weit in den View-Controller-Stack hineinreichen, um Daten festzulegen. Das geht ihn nichts an. Das Geschäft ist der rootViewController. Lassen Sie den rootViewController seine eigenen Kinder behandeln! Wenn ich also den normalen Ladevorgang des Storyboards durch das System umgehen würde, indem ich Verweise darauf in der Datei info.plist entferne, würde ich den rootViewController höchstens mit instanziiereninstantiateViewControllerWithIdentifier:und möglicherweise seine Wurzel, wenn es sich um einen Container wie einen UINavigationController handelt. Was Sie vermeiden möchten, ist das Instanziieren von View-Controllern, die bereits vom Storyboard instanziiert wurden. Das ist ein Problem, das ich sehr sehe. Kurz gesagt, ich bin mit der akzeptierten Antwort nicht einverstanden. Es ist falsch, es sei denn, die Poster bedeuten, das Laden des Storyboards aus der info.plist zu entfernen, da Sie ansonsten 2 Storyboards geladen haben, was keinen Sinn ergibt. Es ist wahrscheinlich kein Speicherverlust, da das System die Stammszene initialisiert und dem Fenster zugewiesen hat, aber dann sind Sie gekommen und haben sie erneut instanziiert und erneut zugewiesen. Ihre App hat einen ziemlich schlechten Start!

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