Reputation: 19469
I have seen lengthy Objective-C answers to this here on stack overflow, but no swift answers.
How can I change the initial view controller programmatically in swift, from a view controller?
I would think it would go something like this:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
storyboard.setInitialViewController(identifier: ViewController())
But no, this doesn't do anything. The first line is good, but the second line's functions just don't exist.
Upvotes: 8
Views: 23365
Reputation: 3817
Updated for Swift 3
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = UINavigationController(rootViewController: ViewController())
return true
}
Upvotes: 5
Reputation: 6495
To do it in the view controller and not in the app delegate: Just fetch the reference to the AppDelegate in your view controller and reset it's window object with the right view controller as it's rootviewController.
Step 1: Make some NSUserDefaults the user can adjust. A couple of buttons, some switches in a table view, something. Then when the user taps the button, we change the NSUserDefault.
@IBAction func SwitchLaunchViewtoViewController2(sender: AnyObject) {
defaults.setObject("ViewController2", forKey: "LaunchView")
}
@IBAction func SwitchLaunchViewtoViewController1(sender: AnyObject) {
defaults.setObject("ViewController1", forKey: "LaunchView")
}
Hook a couple of buttons in a settings view controller up to these functions, and we've started.
Step 2: Set up Storyboard IDs for all the storyboards you want to be able to be set as the launch view. So, for each View Controller that could be an initial view controller:
-Head into your storyboard.
-Click on the view controller.
-In the sidebar at right, click on the newspaper-like icon, which you control the class in.
-In the "Identity" section (third row), check "Use Storyboard ID" (make sure it's on) and then type in something like "VC1" in the "Storyboard ID" text field. Make sure you choose a different Storyboard ID for each view controller.
-Repeat for each view controller.
Step 3: Set up your initial view controller in the AppDelegate.swift file. Head into the func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
section of your app delegate.
Add this to read from the NSUserDefault you created earlier:
let defaults = NSUserDefaults.standardUserDefaults()
if let launchview = defaults.stringForKey("LaunchView")
{
}
This looks for an NSUserDefault string called "LaunchView" (which you created in step 1) and sets it to the new variable launchview if it finds a matching NSUserDefault.
Then, inside the if let launchview...
brackets, we want to check what you set your LaunchView
to. For every object you set to LaunchView in step 1 (in the example, I did "ViewController2"
and "ViewController1"
), you have to check for it here. So, inside those brackets, we add this:
if launchview == "ViewController2" {
} else if launchview == "ViewController1" {
}
Then, inside each of those if statements, we add the following code:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil) // this assumes your storyboard is titled "Main.storyboard"
let yourVC = mainStoryboard.instantiateViewControllerWithIdentifier("YOUR_VC_IDENTIFIER") as! YourViewController // inside "YOUR_VC_IDENTIFIER" substitute the Storyboard ID you created in step 2 for the view controller you want to open here. And substitute YourViewController with the name of your view controller, like, for example, ViewController2.
appDelegate.window?.rootViewController = yourVC
appDelegate.window?.makeKeyAndVisible()
This will open the chosen window when your application finishes loading after it's been in the background a while.
Your finished didFinishLoadingWithOptions
section of your AppDelegate might look something like this:
(don't just copy and paste, read the instructions above)
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
if let launchview = defaults.stringForKey("LaunchView")
{
if launchview == "ViewController1" {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let yourVC = mainStoryboard.instantiateViewControllerWithIdentifier("VC1") as! ViewController1
appDelegate.window?.rootViewController = yourVC
appDelegate.window?.makeKeyAndVisible()
} else if launchview == "ViewController2" {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let yourVC = mainStoryboard.instantiateViewControllerWithIdentifier("VC1") as! ViewController1
appDelegate.window?.rootViewController = yourVC
appDelegate.window?.makeKeyAndVisible()
}
}
return true
}
I hope this helps you, and many thanks to Ankit Goel who helped me with this one so much. Read the comments down below for more.
One final note: if you are using switches in a settings view, make sure on the viewDidLoad of that settings view controller you read from the NSUserDefault LaunchView
which one the user selected last.
Upvotes: 12
Reputation: 23451
First of all, setting the initial view controller programmatically of your app can be made in the application:didFinishLaunchingWithOptions:
using the code exposed in the question:
You can manage all the conditions you want inside it to show one or another UIViewController
in base of conditions.
For example let's say you want in your app show a walkthrough only the first time the app is installed, and after that walktrough another login screen and then another one, but you only show the walkthrough the first time and the login in case of not being logged before and the the another one.
This can be handled in several ways of course, I only try to explain you one of the ways of make it.
For this you can set a controller called SplashViewController for example, it's your initial UIViewController
and inside it you show the image of the app (the big image logo, launchscreen) and your process when you go to one place or another. In this way you clean a lot the code inside your AppDelegate
and it's more easily to make unit test for it.
Now if you want to go to another UIViewController
from inside another UIViewController
you can do it using the following code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewControllerWithIdentifier("ControllerName") as! ControllerName
self.presentViewController(viewController, animated: true, completion: nil)
I hope this help you.
Upvotes: 2