Storyboard - refer to ViewController in AppDelegate
Solution 1
Have a look at the documentation for -[UIStoryboard instantiateViewControllerWithIdentifier:]
. This allows you to instantiate a view controller from your storyboard using the identifier that you set in the IB Attributes Inspector:
EDITED to add example code:
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"
bundle: nil];
MyViewController *controller = (MyViewController*)[mainStoryboard
instantiateViewControllerWithIdentifier: @"<Controller ID>"];
Solution 2
If you use XCode
5 you should do it in a different way.
- Select your
UIViewController
inUIStoryboard
- Go to the
Identity Inspector
on the right top pane - Check the
Use Storyboard ID
checkbox - Write a unique id to the
Storyboard ID
field
Then write your 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;
Solution 3
Generally, the system should be handling view controller instantiation with a storyboard. What you want is to traverse the viewController hierarchy by grabbing a reference to the self.window.rootViewController
as opposed to initializing view controllers, which should already be initialized correctly if you've setup your storyboard properly.
So, let's say your rootViewController
is a UINavigationController and then you want to send something to its top view controller, you would do it like this in your AppDelegate's didFinishLaunchingWithOptions
:
UINavigationController *nav = (UINavigationController *) self.window.rootViewController;
MyViewController *myVC = (MyViewController *)nav.topViewController;
myVC.data = self.data;
In Swift if would be very similar:
let nav = self.window.rootViewController as! UINavigationController;
let myVC = nav.topViewController as! MyViewController
myVc.data = self.data
You really shouldn't be initializing view controllers using storyboard id's from the app delegate unless you want to bypass the normal way storyboard is loaded and load the whole storyboard yourself. If you're having to initialize scenes from the AppDelegate you're most likely doing something wrong. I mean imagine you, for some reason, want to send data to a view controller way down the stack, the AppDelegate shouldn't be reaching way into the view controller stack to set data. That's not its business. It's business is the rootViewController. Let the rootViewController handle its own children! So, if I were bypassing the normal storyboard loading process by the system by removing references to it in the info.plist file, I would at most instantiate the rootViewController using instantiateViewControllerWithIdentifier:
, and possibly its root if it is a container, like a UINavigationController. What you want to avoid is instantiating view controllers that have already been instantiated by the storyboard. This is a problem I see a lot. In short, I disagree with the accepted answer. It is incorrect unless the posters means to remove loading of the storyboard from the info.plist since you will have loaded 2 storyboards otherwise, which makes no sense. It's probably not a memory leak because the system initialized the root scene and assigned it to the window, but then you came along and instantiated it again and assigned it again. Your app is off to a pretty bad start!
Matthias D
Updated on October 16, 2020Comments
-
Matthias D over 3 years
consider the following scenario: I have a storyboard-based app. I add a ViewController object to the storyboard, add the class files for this ViewController into the project and specify the name of the new class in the IB identity inspector. Now how am I going to refer to this ViewController programmatically from the AppDelegate? I've made a variable with the relevant class and turned it into an IBOutlet property, but I don't see any way of being able to refer to the new ViewController in code - any attempt to ctrl-drag a connection doesn't work.
i.e. within the AppDelegate I can get to the base ViewController like this
(MyViewController*) self.window.rootViewController
but how about any other ViewController contained within the storyboard?
-
Matthias D over 12 yearsHi Robin, thanks for that! I looked at this doc but got the words instantiate and initialise mixed up... this gets us there (after following your instruction:) (damn the lack of code formatting in replies...) UIStoryboard* mainStoryboard = [UIStoryboard storyboardWithName: @"MainStoryboard" bundle: nil]; MyViewController* thisController = (MyViewController*) [mainStoryboard instantiateViewControllerWithIdentifier: @"myvc"];
-
Robin Summerhill over 12 yearsI've added your example code to the answer with formatting for anyone who is looking at this.
-
roocell over 12 yearsif you're making a universal app be sure to use MainStoryboard_iPhone/MainStoryboard_iPad otherwise you'll get a crash.
-
carbonr about 12 yearscan you please tell me, how to open this view controller also.
-
bashan about 12 yearsThis code works fine for me. But it seems like the address of the instance of the main view controller in the app delegate is different than the one created later. Any way of solving this?
-
Admin about 12 yearsThis instantiate tells me that it makes a duplicate of ViewController inside storyboard, is it a reference to the one inside the storyboard or a duplicate, if duplicate how can we access the one inside the storyboard
-
user523234 almost 12 years@iPhoneDeveloper: After some testing, I discovered that it created a new instance of ViewController. It is not a reference to the one inside the storyboard. So the old delegate methods pattern is still needed to be used to pass back data to the parent controller.
-
Tad Bumcrot almost 12 yearsFrom within the delegate you can access the storyboard instance loaded by your info.plist like this:
[[[self window] rootViewController] storyboard]
According to the docs this will return the "storyboard from which the view controller originated." (or nil if it didn't come from a storyboard). From that UIStoryboard* you can use the instantiate calls that @RobinSummerhill mentioned. Note that Storyboards instantiate new instances of your viewControllers (scenes) as they are needed and doesn't re-use those that were previously viewed. -
Fahim Parkar over 11 years@roocell : Why there would be crash? I have two storyboard as
MainStoryboard
andMainStoryboard_iPad
. Nothing goes wrong. -
Myron Slaw almost 11 yearsThis does not give you a pointer to the VC within the storyboard (Which is what the OP asked for) this instantiates (as in the method name) a new instance.
-
Robin Summerhill almost 11 years'the VC within the storyboard' makes no sense. There are no instances 'in' the storyboard. The storyboard is essentially the file saved from InterfaceBuilder and you need to instantiate objects specified within it.
-
gnclmorais over 10 yearsAs far as I know and was able to try it out, this is the updated answer.
-
Brian White over 10 yearsA storyboard's name is its filename without the extension so it could also be "Main_iPhone" or "Main_iPad" if you've set up your project that way.
-
lol over 10 yearsand then how do we transition back to the original rootViewController after login. At least to my knowledge of iOS 7 and Xcode 5.0.2 - changing the root view controller back will immediate and without animation switch the view hierarchy. The UX team have murdered coders for less.
-
Fattie about 10 yearsI believe the OP wants to know HOW TO GET AT the CURRENTLY RUNNING vc. Not how to load one. Exactly as he explains, you used to be able to say this self.window.rootViewController and now you can't any more.
-
Leo Dabus over 9 yearsHow would I do that using Swift?