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.
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;
}
didFinishLaunchingWithOptions
method? I need to switch between onboarding/regular app and didFinishLaunchingWithOptions
is only called when you install the app. –
Marabout didFinishLaunchingWithOptions
is called when the app is started in a new process. If you go to the home screen and return to the app, this method will not be invoked again. (Unless iOS terminates due to memory constraints.) Try stopping the app and launch once again from your IDE. If problem continues, post the issue to SO and I'll be happy to help, friend. –
Miriam self.window = UIWindow(frame: UIScreen.mainScreen().bounds) var storyboard = UIStoryboard(name: "Main", bundle: nil) var viewController: UIViewController = // self.window!.rootViewController = viewController self.window!.makeKeyAndVisible()
–
Dolichocephalic application:willFinishLaunchingWithOptions:
? –
Decline 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:
- Create a new window with the size of the current window and set it as our main window
- Instantiate a storyboard that we can use to create our new initial view controller
- Instantiate our new initial view controller based on it's Storyboard ID
- Set our new window's root view controller as our the new controller we just initiated
- Make our new window visible
Enjoy and happy programming!
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;
}
init()
/ deinit()
cycle, but without executing viewDidLoad()
or properly initializing IBOutlet
-s. Make sure you code is ready for it. –
Jacobba UIDocumentBrowserViewController
while conditionally maintaining support for iOS 10.x users via whatever existing mechanism was used. –
Haruspicy SWIFT 5
If you don't have a ViewController set as the initial ViewController in storyboard, you need to do 2 things:
- Go to your project TARGETS, select your project -> General -> Clear the Main Interface field.
- 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()
}
Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set
warning I was having after I decided to instantiate my initial VC in code. An important point, when @Geek says "delete the storyboard name field", they mean the whole row of the plist, not just the content of the field itself. –
Antabuse UIWindow(windowScene: windowScene)
is a different UIWindow initializer than the initWithFrame:
you were probably using in older App Delegate-based code. Make sure to update that if you are porting to the new way of doing things. Using the old Window initializer was causing a black screen. –
Joashus 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
}
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
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.
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.
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
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).
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
}
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.
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!)
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.
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()
}
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:
rootVC
from instantiateViewControllerWithIdentifier
, correct? –
Billie 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
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
}
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**
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()
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
}
}
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
Set initial ViewController using Storyboards(instead of Main)
Main.storyboard
-> View Controller -> Attributes Inspector -> UncheckIs Initial View Controller
App target -> General -> remove all from
Main Interface
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
}
}
Following code is objective c.
Following code will create your custom entry file without storyboard.
All answers I read on stack overflow have the following code but they are missing important line
MainViewController is the viewController that I want to be the first view controller to be loaded.
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
UIWindowScene *winScreen = (UIWindowScene *)scene;
self.window = [[UIWindow alloc] initWithWindowScene:winScreen];
// Create a root view controller and set it as the root view controller of the navigation controller
MainViewController *rootViewController = [[MainViewController alloc] init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
// Set the navigation controller as the root view controller of the window
[self.window setRootViewController:navigationController];
[self.window makeKeyAndVisible];
}
here I don't know why but each answer does not mention the first line
UIWindowScene *winScreen = (UIWindowScene *)scene;
This code should be added to SceneDelegate.m file Now we could delete main.storyboard file and after deleting this file, we must also delete the two references from info.plist
in project configuration > Info tab > delete Main screen interface file base name
also in project configuration > Info tab > Application scene manifest > Scene configuration > Application session role > Item 0 > delete Storyboard name
Image referring to which reference to delete
Note: This method works now when I am posting this answer but may not work in the future as the new version releases, so keep updating yourself.
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.
© 2022 - 2024 — McMap. All rights reserved.