Programmatically set the initial view controller using Storyboards

IosObjective CSwiftUiviewcontrollerUistoryboard

Ios Problem Overview


How do I programmatically set the InitialViewController for a Storyboard? I want to open my storyboard to a different view depending on some condition which may vary from launch to launch.

Ios Solutions


Solution 1 - Ios

How to without a dummy initial view controller

Ensure all initial view controllers have a Storyboard ID.

In the storyboard, uncheck the "Is initial View Controller" attribute from the first view controller.

If you run your app at this point you'll read:

> Failed to instantiate the default view controller for UIMainStoryboardFile 'MainStoryboard' - perhaps the designated entry point is not set?

And you'll notice that your window property in the app delegate is now nil.

In the app's setting, go to your target and the Info tab. There clear the value of Main storyboard file base name. On the General tab, clear the value for Main Interface. This will remove the warning.

Create the window and desired initial view controller in the app delegate's application:didFinishLaunchingWithOptions: method:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];

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

    UIViewController *viewController = // determine the initial view controller here and instantiate it with [storyboard instantiateViewControllerWithIdentifier:<storyboard id>];

    self.window.rootViewController = viewController;
    [self.window makeKeyAndVisible];

    return YES;
}

Solution 2 - Ios

For all the Swift lovers out there, here is the answer by @Travis translated into SWIFT:

Do what @Travis explained before the Objective C code. Then,

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
    
    self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
    let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
    var exampleViewController: ExampleViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ExampleController") as! ExampleViewController
    
    self.window?.rootViewController = exampleViewController
    
    self.window?.makeKeyAndVisible()
    
    return true
}

The ExampleViewController would be the new initial view controller you would like to show.

The steps explained:

  1. Create a new window with the size of the current window and set it as our main window
  2. Instantiate a storyboard that we can use to create our new initial view controller
  3. Instantiate our new initial view controller based on it's Storyboard ID
  4. Set our new window's root view controller as our the new controller we just initiated
  5. Make our new window visible

Enjoy and happy programming!

Solution 3 - Ios

You can programmatically set the key window's rootViewController in (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions

for example:

- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if (shouldShowAnotherViewControllerAsRoot) {
        UIStoryboard *storyboard = self.window.rootViewController.storyboard;
        UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:@"rootNavigationController"];
        self.window.rootViewController = rootViewController;
        [self.window makeKeyAndVisible];
    }

    return YES;
}

Solution 4 - Ios

SWIFT 5

If you don't have a ViewController set as the initial ViewController in storyboard, you need to do 2 things:

  1. Go to your project TARGETS, select your project -> General -> Clear the Main Interface field.
  2. Always inside project TARGETS, now go to Info -> Application Scene Manifest -> Scene Configuration -> Application Session Role -> Item0 (Default Configuration) -> delete the storyboard name field.

Finally, you can now add your code in SceneDelegate:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
    // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
    // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
    guard let windowScene = (scene as? UIWindowScene) else { return }
    
    window = UIWindow(windowScene: windowScene)
    
    
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    // Make sure you set an Storyboard ID for the view controller you want to instantiate
    window?.rootViewController = storyboard.instantiateViewController(withIdentifier: identifier)
    window?.makeKeyAndVisible()

}

Solution 5 - Ios

Swift 3: Update to @victor-sigler's code

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    self.window = UIWindow(frame: UIScreen.main.bounds)

    // Assuming your storyboard is named "Main"
    let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)

    // Add code here (e.g. if/else) to determine which view controller class (chooseViewControllerA or chooseViewControllerB) and storyboard ID (chooseStoryboardA or chooseStoryboardB) to send the user to
    
    if(condition){
        let initialViewController: chooseViewControllerA = mainStoryboard.instantiateViewController(withIdentifier: "chooseStoryboardA") as! chooseViewControllerA
        self.window?.rootViewController = initialViewController
    )
    }else{
        let initialViewController: chooseViewControllerB = mainStoryboard.instantiateViewController(withIdentifier: "chooseStoryboardB") as! chooseViewControllerB
        self.window?.rootViewController = initialViewController
    )

    self.window?.makeKeyAndVisible(

    return true
}

Solution 6 - Ios

You can set Navigation rootviewcontroller as a main view controller. This idea can use for auto login as per application requirement.

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

UIViewController viewController = (HomeController*)[mainStoryboard instantiateViewControllerWithIdentifier: @"HomeController"];

UINavigationController navController = [[UINavigationController alloc] initWithRootViewController:viewController];

 self.window.rootViewController = navController;

if (NSFoundationVersionNumber > NSFoundationVersionNumber_iOS_6_1) {

    // do stuff for iOS 7 and newer

    navController.navigationBar.barTintColor = [UIColor colorWithRed:88/255.0 green:164/255.0 blue:73/255.0 alpha:1.0];

    navController.navigationItem.leftBarButtonItem.tintColor = [UIColor colorWithRed:88/255.0 green:164/255.0 blue:73/255.0 alpha:1.0];

    navController.navigationBar.tintColor = [UIColor whiteColor];

    navController.navigationItem.titleView.tintColor = [UIColor whiteColor];

    NSDictionary *titleAttributes =@{

                                     NSFontAttributeName :[UIFont fontWithName:@"Helvetica-Bold" size:14.0],

                                     NSForegroundColorAttributeName : [UIColor whiteColor]

                                     };

    navController.navigationBar.titleTextAttributes = titleAttributes;

    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];

}

else {

    // do stuff for older versions than iOS 7

    navController.navigationBar.tintColor = [UIColor colorWithRed:88/255.0 green:164/255.0 blue:73/255.0 alpha:1.0];



    navController.navigationItem.titleView.tintColor = [UIColor whiteColor];

}

[self.window makeKeyAndVisible];

For StoryboardSegue Users

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

// Go to Login Screen of story board with Identifier name : LoginViewController_Identifier

LoginViewController *loginViewController = (LoginViewController*)[mainStoryboard instantiateViewControllerWithIdentifier:@“LoginViewController_Identifier”];

navigationController = [[UINavigationController alloc] initWithRootViewController:testViewController];

self.window.rootViewController = navigationController;

[self.window makeKeyAndVisible];

// Go To Main screen if you are already Logged In Just check your saving credential here

if([SavedpreferenceForLogin] > 0){
    [loginViewController performSegueWithIdentifier:@"mainview_action" sender:nil];
}

Thanks

Solution 7 - Ios

Open mainstoryboard, select the view that you want start first, then open Utilities--> Attributes. Below the "View Controller" you see the "Is initial View Controller" radio button. Just select it.

--- To the revised question:

May be you can try this: write a method in ViewDidLoad section of your inital view and when the method runs on application launch, method triggers a segue to another view.

Solution 8 - Ios

I don't think it's possible. Instead you can have one initial controller which will have segues to different view controllers. On startup, you can decide which segue to perform programmatically.

Solution 9 - Ios

You can set initial view controller using Interface Builder as well as programmatically.

Below is approach used for programmatically.

Objective-C :

        self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
        UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
        
        UIViewController *viewController = [storyboard instantiateViewControllerWithIdentifier:@"HomeViewController"]; // <storyboard id>
        
        self.window.rootViewController = viewController;
        [self.window makeKeyAndVisible];
        
        return YES;

Swift :

        self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        
        var objMainViewController: MainViewController = mainStoryboard.instantiateViewControllerWithIdentifier("MainController") as! MainViewController
        
        self.window?.rootViewController = objMainViewController
        
        self.window?.makeKeyAndVisible()
        
        return true

Solution 10 - Ios

In AppDelegate.swift you can add the following code:

let sb = UIStoryboard(name: "Main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "YourViewController_StorboardID")
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()

Of course, you need to implement your logic, based on which criteria you'll choose an appropriate view controller.

Also, don't forget to add an identity (select storyboard -> Controller Scene -> Show the identity inspector -> assign StorboardID).

Solution 11 - Ios

Another solution with using Swift 3 and Swift 4 with avoiding force casting is like this

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    self.window = UIWindow(frame: UIScreen.main.bounds)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    guard let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewController") as? YourViewController else {
        return false
    }
    self.window?.rootViewController = viewController
    self.window?.makeKeyAndVisible()
    return true
}

And below is using with UINavigationController

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    self.window = UIWindow(frame: UIScreen.main.bounds)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    guard let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewController") as? YourViewController else {
        return false
    }
    let navigationController = UINavigationController(rootViewController: viewController)
    self.window?.rootViewController = navigationController
    self.window?.makeKeyAndVisible()
    return true
}

Solution 12 - Ios

If you are using Scene Delegates in iOS 13+:

Make sure in your Info.plist file you find the row at:

Application Scene Manifest > Scene Configuration > Application Session Role > Item 0

and delete the reference to the Main Storyboard there as well. Otherwise you'll get the same warning about failing to instantiate from storyboard.

Also, move the code from the app delegate to the scene delegate method scene(_:willConnectTo:options:), since this is where life cycle events are handled now.

Solution 13 - Ios

I created a routing class to handle dynamic navigation and keep clean AppDelegate class, I hope it will help other too.

//
//  Routing.swift
// 
//
//  Created by Varun Naharia on 02/02/17.
//  Copyright © 2017 TechNaharia. All rights reserved.
//

import Foundation
import UIKit
import CoreLocation

class Routing {
    
    class func decideInitialViewController(window:UIWindow){
        let userDefaults = UserDefaults.standard
        if((Routing.getUserDefault("isFirstRun")) == nil)
        {
            Routing.setAnimatedAsInitialViewContoller(window: window)
        }
        else if((userDefaults.object(forKey: "User")) != nil)
        {
            Routing.setHomeAsInitialViewContoller(window: window)
        }
        else
        {
            Routing.setLoginAsInitialViewContoller(window: window)
        }
        
    }
    
    class func setAnimatedAsInitialViewContoller(window:UIWindow) {
        Routing.setUserDefault("Yes", KeyToSave: "isFirstRun")
        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let animatedViewController: AnimatedViewController = mainStoryboard.instantiateViewController(withIdentifier: "AnimatedViewController") as! AnimatedViewController
        
        window.rootViewController = animatedViewController
        window.makeKeyAndVisible()
    }
    
    class func setHomeAsInitialViewContoller(window:UIWindow) {
        let userDefaults = UserDefaults.standard
        let decoded  = userDefaults.object(forKey: "User") as! Data
        User.currentUser = NSKeyedUnarchiver.unarchiveObject(with: decoded) as! User
        
        if(User.currentUser.userId != nil && User.currentUser.userId != "")
        {
            let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
            let homeViewController: HomeViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
            let loginViewController: UINavigationController = mainStoryboard.instantiateViewController(withIdentifier: "LoginNavigationViewController") as! UINavigationController
            loginViewController.viewControllers.append(homeViewController)
            window.rootViewController = loginViewController
        }
        window.makeKeyAndVisible()
    }
    
    class func setLoginAsInitialViewContoller(window:UIWindow) {
        let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
        let loginViewController: UINavigationController = mainStoryboard.instantiateViewController(withIdentifier: "LoginNavigationViewController") as! UINavigationController
        
        window.rootViewController = loginViewController
        window.makeKeyAndVisible()
    }
    
  class func setUserDefault(_ ObjectToSave : Any?  , KeyToSave : String)
    {
        let defaults = UserDefaults.standard
        
        if (ObjectToSave != nil)
        {
            
            defaults.set(ObjectToSave, forKey: KeyToSave)
        }
        
        UserDefaults.standard.synchronize()
    }
    
    class func getUserDefault(_ KeyToReturnValye : String) -> Any?
    {
        let defaults = UserDefaults.standard
        
        if let name = defaults.value(forKey: KeyToReturnValye)
        {
            return name as Any
        }
        return nil
    }
    
    class func removetUserDefault(_ KeyToRemove : String)
    {
        let defaults = UserDefaults.standard
        defaults.removeObject(forKey: KeyToRemove)
        UserDefaults.standard.synchronize()
    }
    
}

And in your AppDelegate call this

 self.window = UIWindow(frame: UIScreen.main.bounds)
 Routing.decideInitialViewController(window: self.window!)

Solution 14 - Ios

A few days ago I've encountered to same situation. A very simple trick solved this problem. I set hidden my initial view controller before launch2. If initial view controller is the right controller it's set to visible in viewDidLoad. Else, a segue is performed to desired view controller. It works perfectly in iOS 6.1 and above. I'm sure it works on earlier versions of iOS.

Solution 15 - Ios

Thanks modified this as follows in AppDelegate:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) ->     Bool {
//Some code to check value of pins
	
if pins! == "Verified"{
		print(pins)
		self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
		let mainStoryboard: UIStoryboard = UIStoryboard(name: "HomePage", bundle: nil)
		let exampleViewController: UINavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("SBHP") as! UINavigationController
		
		self.window?.rootViewController = exampleViewController
		
		self.window?.makeKeyAndVisible()
	}else{
		print(pins)
		self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
		let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
		let exampleViewController: UINavigationController = mainStoryboard.instantiateViewControllerWithIdentifier("SBUser") as! UINavigationController
		
		self.window?.rootViewController = exampleViewController
		
		self.window?.makeKeyAndVisible()
	}

Solution 16 - Ios

Found simple solution - no need to remove "initial view controller check" from storyboard and editing project Info tab and use makeKeyAndVisible, just place

self.window.rootViewController = rootVC;

in

- (BOOL) application:didFinishLaunchingWithOptions:

Solution 17 - Ios

let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewController(withIdentifier: "storyBoardid") as! ViewController
let navigationController = UINavigationController(rootViewController: vc)
UIApplication.shared.delegate.window?.rootViewController = navigationController

Another way is to present viewController,

let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewController(withIdentifier: "storyBoardid") as! ViewController
self.present(vc,animated:true,completion:nil)

First you need to create object of your storyboard then change root(if required) then you take reference of particular view controller which is pushed current view controller(if you change root) else it's just present new view controller which may you

Solution 18 - Ios

Swift 4, Xcode 9

in file AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let firstVC = storyboard.instantiateViewController(withIdentifier: "firstViewController") as! firstViewController
    self.window?.rootViewController = firstVC
}

Solution 19 - Ios

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        self.window = UIWindow(frame: UIScreen.main.bounds)
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        if (PreferenceHelper.getAccessToken() != "") {
            let initialViewController = storyboard.instantiateViewController(withIdentifier: "your View Controller Identifier")
            self.window?.rootViewController = initialViewController
        } else {
            let initialViewController = storyboard.instantiateViewController(withIdentifier: "your View Controller identifier")
            self.window?.rootViewController = initialViewController
        }
        self.window?.makeKeyAndVisible()
        return true
    }

/*
use your view Controller identifier must use it doubles quotes**strong text**

Solution 20 - Ios

Swift 5 or above# make route view controller by this simple code. If you are using xcode 11 or above first initialise var window: UIWindow? in AppDelegate

let rootVC = mainStoryboard.instantiateViewController(withIdentifier: "YOURCONTROLLER") as! YOURCONTROLLER
        
        navigationController.setNavigationBarHidden(true, animated: true)
        UIApplication.shared.windows.first?.rootViewController = UINavigationController.init(rootViewController: rootVC)
        UIApplication.shared.windows.first?.makeKeyAndVisible()

Solution 21 - Ios

If you prefer not to change applicationDidFinish, you can do the following trick:

Set Navigation controller as an initial view controller and assign to it a custom class 'MyNavigationController'. Then you can tweak its root view controller during viewDidLoad - it will override the root view controller that you set in your storyboard.

class MyNavigationController: UINavigationController {
    override func viewDidLoad() {
        super.viewDidLoad()
        if !isLoggedIn() {
            viewControllers = [R.storyboard.authentication.loginView()!]
        }
    }
    
    private func isLoggedIn() -> Bool {
        return false
    }

}

Solution 22 - Ios

Xcode 12.4 Swift 5

in SceneDelegate.Swift

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: windowScene)
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    window.rootViewController = storyboard.instantiateViewController(withIdentifier: "UserViewController") as! UserViewController
    
    self.window = window
    window.makeKeyAndVisible()
}

You can add your condition which view controller scene will dispaly

Solution 23 - Ios

Set initial ViewController using Storyboards(instead of Main)

[Swift 5 and Xcode 11]

  1. Main.storyboard -> View Controller -> Attributes Inspector -> Uncheck Is Initial View Controller

  2. App target -> General -> remove all from Main Interface

  3. Edit App delegate

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        self.window = UIWindow(frame: UIScreen.main.bounds)
        
        let storyboard: UIStoryboard = UIStoryboard(name: "SomeStoryboard", bundle: nil) //SomeStoryboard  is name of .storyboard
        let viewController: ViewController = storyboard.instantiateViewController(withIdentifier: "someStoryboardId") as! ViewController //someStoryboardId is Storyboard ID

        self.window?.rootViewController = viewController
        self.window?.makeKeyAndVisible()

        return true
    }
}

Solution 24 - Ios

Select the view controller which you want to open first and go to attribute inspector. Go to initial scene and check is initial view controller option.

Now this will be your initial view controller that will open first when application launch.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJagdev SendhavView Question on Stackoverflow
Solution 1 - IosTravisView Answer on Stackoverflow
Solution 2 - IosDisplay nameView Answer on Stackoverflow
Solution 3 - IosChengjiongView Answer on Stackoverflow
Solution 4 - Iosrs7View Answer on Stackoverflow
Solution 5 - IosMEKView Answer on Stackoverflow
Solution 6 - IosBhavsar1311View Answer on Stackoverflow
Solution 7 - Iosm.etkaView Answer on Stackoverflow
Solution 8 - IosShmidtView Answer on Stackoverflow
Solution 9 - IosJayprakash DubeyView Answer on Stackoverflow
Solution 10 - IosNedim TalovicView Answer on Stackoverflow
Solution 11 - IosabdullahselekView Answer on Stackoverflow
Solution 12 - Iosbze12View Answer on Stackoverflow
Solution 13 - IosVarun NahariaView Answer on Stackoverflow
Solution 14 - Iosm.etkaView Answer on Stackoverflow
Solution 15 - IosJeremyView Answer on Stackoverflow
Solution 16 - Iosalex1704View Answer on Stackoverflow
Solution 17 - IosV D PurohitView Answer on Stackoverflow
Solution 18 - IosShan YeView Answer on Stackoverflow
Solution 19 - IoscharlesView Answer on Stackoverflow
Solution 20 - IosRohit NishadView Answer on Stackoverflow
Solution 21 - IosKamen DobrevView Answer on Stackoverflow
Solution 22 - IosNehaView Answer on Stackoverflow
Solution 23 - IosyoAlex5View Answer on Stackoverflow
Solution 24 - IosiMashView Answer on Stackoverflow