Access a UIViewCotroller in AppDelegate in Swift - ios

I want to access a UIViewcontroller in AppDelegate. The hierarchy is shown here:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let navController = self.window!.rootViewController as! UINavigationController
let tabController = navController.topViewController as! UITabBarController
var postController = tabController.topViewController as! UITableViewController
// It is incorrect. has no member of topViewController
return true
}

Have you tried something like:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let navController = self.window!.rootViewController as! UINavigationController
let tabController = navController.topViewController as! UITabBarController
var postController = tabController.viewControllers[0]
// It is incorrect. has no member of topViewController
return true
}
Tab bar controller manages a list of ViewControllers. In this case you want the first one in the list. Note the syntax might be a bit wrong as I don't have much swift experience!
var postController = tabController.viewControllers[0]
That is the part I cahanged.

if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController {
while let presentedViewController = topController.presentedViewController {
topController = presentedViewController
}
// topController should now be your topmost view controller
}

The problem is that you shouldn't have to access you controller from AppDelegate, it's a mistake in your app's architecture.
AppDelegate should only be used for app's lifecycle (launch/activation/deactivation/push notifications/...)
Why would you like to access your viewController here ?

you already did your forwarding with the storyboard,
all you have to do is:
func applicationDidFinishLaunching(_ application: UIApplication) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = storyboard.instantiateViewController(withIdentifier: "navigationController") // here you should insert your identifier (storyboard -> navigationcontroller -> Identity -> Storyboard ID)
window!.rootViewController = navigationController
window!.makeKeyAndVisible()
}

You can use storyboard identifier to access the view controller
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "storyboardIdentifier")

Related

Could not cast value of view controllers error

My app was building fine until today when all of a sudden I got the following errors after a successful build:
Could not cast value of type 'FirebaseApp.HomeViewController' (0x101ab6aa0) to 'FirebaseApp.MenuViewController' (0x101ab6d30).
Could not cast value of type 'FirebaseApp.HomeViewController' (0x101ab6aa0) to 'FirebaseApp.MenuViewController' (0x101ab6d30).
The line in my app delegate
let controller = storyboard.instantiateViewController(withIdentifier:
"mainView") as! MenuViewController
was then highlighted red within this AppDelegate Class:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// Override point for customization after application launch.
let authListener = Auth.auth().addStateDidChangeListener { auth, user in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if user != nil {
//
let controller = storyboard.instantiateViewController(withIdentifier: "MainTabBarController") as! UITabBarController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
} else {
// main screen
let controller = storyboard.instantiateViewController(withIdentifier: "mainView") as! MenuViewController
self.window?.rootViewController = controller
self.window?.makeKeyAndVisible()
}
}
return true
}
I have in my storyboard the mainView identified:
And I have a HomeViewController
class HomeViewController:UIViewController, UITableViewDelegate, UITableViewDataSource {
which has the bulk of my code.
I am not sure what went wrong here, but I suspect it has something to do with misnaming in my story board.
Edit: I solved this problem by changing "mainView" to "MenuViewController"
In the storyboard for MenuViewController you need to set mainView as Storyboard ID not the Restoration ID.
Like below image:

How to go to the what I want controller when application didFinishLaunching

When I launching my application, I want go to the custom view controller, but the default first controller in storyboard:
I want go to brown vc when launch my app:
My method is below, but get a black screen with Unable to capture view hierarchy
1) In Info.plist, delete the Main storyboard file base name line.
2) In my Appdelegate.swift:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let sb:UIStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
let nav: CustomNavController = sb.instantiateViewController(withIdentifier: "CustomNavController") as! CustomNavController
let red_vc:ViewController = sb.instantiateViewController(withIdentifier: "ViewController") as! ViewController
let green_vc:ViewController2 = sb.instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
let brown_vc:ViewController3 = sb.instantiateViewController(withIdentifier: "ViewController3") as! ViewController3
nav.viewControllers = [red_vc, green_vc, brown_vc]
self.window? = UIWindow.init(frame: UIScreen.main.bounds)
self.window?.rootViewController = nav
self.window?.makeKeyAndVisible()
return true
}
Result get a black screen:
Is which step I mistake? and how can I get it well ? When launch my application I want go to brown vc.
ATTEMPT - 1
Using push to brown vc, it is not work too:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let sb:UIStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
let nav: CustomNavController = sb.instantiateViewController(withIdentifier: "CustomNavController") as! CustomNavController
let red_vc:ViewController = sb.instantiateViewController(withIdentifier: "ViewController") as! ViewController
let green_vc:ViewController2 = sb.instantiateViewController(withIdentifier: "ViewController2") as! ViewController2
let brown_vc:ViewController3 = sb.instantiateViewController(withIdentifier: "ViewController3") as! ViewController3
//nav.viewControllers = [red_vc, green_vc, brown_vc]
nav.pushViewController(red_vc, animated: false)
nav.pushViewController(green_vc, animated: false)
nav.pushViewController(brown_vc, animated: false)
self.window? = UIWindow.init(frame: UIScreen.main.bounds)
self.window?.rootViewController = nav
self.window?.makeKeyAndVisible()
return true
}
You no need delete Main storyboard file base name in Info.plist
In AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let mainStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
let brownVC = mainStoryboard.instantiateViewController(withIdentifier: "brownVCIdentifier") as! BrownViewController
let navigationController = application.windows[0].rootViewController as! UINavigationController
navigationController.isNavigationBarHidden = true
navigationController.pushViewController(brownVC, animated: false)
return true
}
(or)
In RedViewController(first viewController):
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let brownVC = storyboard?.instantiateViewController(withIdentifier: "brownVCIdentifier") as! BrownViewController
navigationController?.isNavigationBarHidden = true
navigationController?.pushViewController(brownVC, animated: false)
}
Github link:
https://github.com/k-sathireddy/DirectNavigationSample
You are setting the root viewcontroller as nav which has no UIView and it's creating a blank view due to which you see the black view when app is launched.
this code nav.viewControllers = [red_vc, green_vc, brown_vc] is not making any sense as you cannot set view controllers like this for UINavigationController. Navigation controller works with PUSH/POP mechanism hence you need to push the view controllers on nav controller which will correctly setup the view hierarchy. Push the controllers to brown_vc in nav and it should work.

iOS Swift SlideMenuControllerSwift

I am learning to develop iOS and come across to this awesome library SlideMenuController. I am able to make use of this library to create awesome slide menu easily.
However, there are some problem that I am facing during implementing with this library.
Environment
In my project storyboard, I have 1 TabBarViewController and 2 ViewController which is under this TabBarViewController. I also have 2 independent ViewController which are LoginViewController and LeftMenuViewController.
I have below code in my AppDelegate.swift file
...
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateViewControllerWithIdentifier("TabBarViewController") as! TabBarViewController
let leftViewController = storyboard.instantiateViewControllerWithIdentifier("LeftMenuViewController") as! LeftMenuViewController
let slideMenuController = SlideMenuController(mainViewController: mainViewController, leftMenuViewController: leftViewController)
SlideMenuOptions.contentViewScale = 1
SlideMenuOptions.hideStatusBar = false;
self.window?.rootViewController = slideMenuController
self.window?.makeKeyAndVisible()
return true
}
...
Everything work perfectly if I don't need my login view as a initial view. I notice that this line of code self.window?.rootViewController = slideMenuController will always make sure that view in mainViewController to be the initial view when the app open.
How can I have my LoginView as the initial view when my app start up and the slide menu is still bind to the TabBarViewController and working properly?
I have try to move the code from AppDelegate.swift to viewDidLoad() function in TabBarViewController.swift but no luck. It is not working.
Need some guilds and help on this. Thanks.
you can use this code instead of yours :
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateViewControllerWithIdentifier("TabBarViewController") as! TabBarViewController
let leftViewController = storyboard.instantiateViewControllerWithIdentifier("LeftMenuViewController") as! LeftMenuViewController
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as! LoginViewController
let nvc: UINavigationController = UINavigationController(rootViewController: loginViewController)
leftViewController.mainVC = nvc
let slideMenuController = SlideMenuController(mainViewController: nvc, leftMenuViewController: leftViewController)
SlideMenuOptions.contentViewScale = 1
SlideMenuOptions.hideStatusBar = false;
self.window?.rootViewController = slideMenuController
self.window?.makeKeyAndVisible()
return true
}
dont forget to add this variable in your LeftMenuViewController
var mainVC : UIViewController!

How to set UITabBarController when setting initial view controller in app delegate

I need to programatically set initial view controller (based on user login status).
This is my initial code:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainRootController = storyboard.instantiateViewControllerWithIdentifier("MainViewController") as UIViewController
if self.window != nil {
let navigationController:UINavigationController = storyboard.instantiateInitialViewController() as UINavigationController
navigationController.viewControllers = [mainRootController]
self.window!.rootViewController = navigationController
}
return true
This loads 'MainViewController' fine. But I am missing UITabBarController also and I don't know how to set it up programatically here.
Any help?
Try this one:
let tabBar = UITabBarController()
tabBar.viewControllers = [navigationController]
self.window!.rootViewController

set initial viewcontroller in appdelegate - swift

I would like to set the initial viewcontroller from the appdelegate. I found a really good answer, however it's in Objective C and im having trouble achieving the same thing in swift.
Programmatically set the initial view controller using Storyboards
- (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;
}
Anyone able to help?
I want the initial Viewcontroller to be dependent on certain conditions being met using a conditional statement.
Xcode11 and SceneDelegate note:
Starting from Xcode11, because of SceneDelegates, it's likely that you shouldn't do it inside AppDelegate. Instead do it from SceneDelegate. For more on that see this other answer
Old answer:
I used this thread to help me convert the objective C to swift, and its working perfectly.
Instantiate and Present a viewController in Swift
Swift 2 code:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("LoginSignupVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
Swift 3 code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginSignupVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
For new Xcode 11.xxx and Swift 5.xx, where the target it set to iOS 13+.
For the new project structure, AppDelegate does not have to do anything regarding rootViewController.
A new class is there to handle window(UIWindowScene) class -> 'SceneDelegate' file.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = // Your RootViewController in here
self.window = window
window.makeKeyAndVisible()
}
}
Try this. For example:
You should use UINavigationController as the initial view controller. Then, you can set any view controller as root from the storyboard.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = storyboard.instantiateInitialViewController() as UINavigationController
let rootViewController = storyboard.instantiateViewControllerWithIdentifier("VC") as UIViewController
navigationController.viewControllers = [rootViewController]
self.window?.rootViewController = navigationController
return true
}
See my storyboard screen.
Swift 3, Swift 4:
Change first line to
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
the rest is same.
Swift 5+:
Instantiate root view controller from storyboard:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// this line is important
self.window = UIWindow(frame: UIScreen.main.bounds)
// In project directory storyboard looks like Main.storyboard,
// you should use only part before ".storyboard" as its name,
// so in this example name is "Main".
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
// controller identifier sets up in storyboard utilities
// panel (on the right), it is called 'Storyboard ID'
let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
return true
}
If you want to use UINavigationController as root:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// this line is important
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController
let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
Instantiate root view controller from xib:
It is almost the same, but instead of lines
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "YourViewControllerIdentifier") as! YourViewController
you'll have to write
let viewController = YourViewController(nibName: "YourViewController", bundle: nil)
if you are not using storyboard, you can try this
var window: UIWindow?
var initialViewController :UIViewController?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
initialViewController = MainViewController(nibName:"MainViewController",bundle:nil)
let frame = UIScreen.mainScreen().bounds
window = UIWindow(frame: frame)
window!.rootViewController = initialViewController
window!.makeKeyAndVisible()
return true
}
Code for Swift 4.2 and 5 code:
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "dashboardVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
And for Xcode 11+ and for Swift 5+ :
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = // Your RootViewController in here
self.window = window
window.makeKeyAndVisible()
}
}
}
Here is a good way to approach it. This example places a navigation controller as the root view controller, and puts the view controller of your choice within it at the bottom of the navigation stack, ready for you to push whatever you need to from it.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
// mainStoryboard
let mainStoryboard = UIStoryboard(name: "MainStoryboard", bundle: nil)
// rootViewController
let rootViewController = mainStoryboard.instantiateViewControllerWithIdentifier("MainViewController") as? UIViewController
// navigationController
let navigationController = UINavigationController(rootViewController: rootViewController!)
navigationController.navigationBarHidden = true // or not, your choice.
// self.window
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
self.window!.rootViewController = navigationController
self.window!.makeKeyAndVisible()
}
To make this example work you would set "MainViewController" as the Storyboard ID on your main view controller, and the storyboard's file name in this case would be "MainStoryboard.storyboard". I rename my storyboards this way because Main.storyboard to me is not a proper name, particularly if you ever go to subclass it.
I had done it in Objective-C. I hope it will be useful for you.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *viewController;
NSUserDefaults *loginUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *check=[loginUserDefaults objectForKey:#"Checklog"];
if ([check isEqualToString:#"login"]) {
viewController = [storyboard instantiateViewControllerWithIdentifier:#"SWRevealViewController"];
} else {
viewController = [storyboard instantiateViewControllerWithIdentifier:#"LoginViewController"];
}
self.window.rootViewController = viewController;
[self.window makeKeyAndVisible];
Init ViewController in AppDelegate
[Initial View Controller]
Disable Main.storyboard
General -> Deployment Info -> Main Interface -> remove `Main`
Info.plist -> remove Key/Value for `UISceneStoryboardFile` and `UIMainStoryboardFile`
Add Storyboard ID
Main.storyboard -> Select View Controller -> Inspectors -> Identity inspector -> Storyboard ID -> e.g. customVCStoryboardId
[previos]
Swift 5 and Xcode 11
Extend UIWindow
class CustomWindow : UIWindow {
//...
}
Edit generated by Xcode SceneDelegate.swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: CustomWindow!
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "customVCStoryboardId")
//or if your storyboard has `Is Initial View Controller`
let storyboard = UIStoryboard(name: String(describing: SomeViewController.self), bundle: nil)
let initialViewController = storyboard.instantiateInitialViewController()
window = CustomWindow(windowScene: windowScene)
window.rootViewController = initialViewController
window.makeKeyAndVisible()
}
//...
}
[Access to Framework bundle]
[Get storyboard from a framework]
If you're not using the storyboard. You can initialize your main view controller programmatically.
Swift 4
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let rootViewController = MainViewController()
let navigationController = UINavigationController(rootViewController: rootViewController)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
class MainViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
}
}
And also remove Main from Deployment Info.
I had done in Xcode 8 and swift 3.0 hope it will be useful for u, and its working perfectly. Use following code :
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "ViewController")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
And If you are using the navigation controller, then use following code for that:
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController:UINavigationController = storyboard.instantiateInitialViewController() as! UINavigationController
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("ViewController")
navigationController.viewControllers = [initialViewController]
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
Swift 4:
Add these lines inside AppDelegate.swift, within the didFinishLaunchingWithOptions() function...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Setting the Appropriate initialViewController
// Set the window to the dimensions of the device
self.window = UIWindow(frame: UIScreen.main.bounds)
// Grab a reference to whichever storyboard you have the ViewController within
let storyboard = UIStoryboard(name: "Name of Storyboard", bundle: nil)
// Grab a reference to the ViewController you want to show 1st.
let initialViewController = storyboard.instantiateViewController(withIdentifier: "Name of ViewController")
// Set that ViewController as the rootViewController
self.window?.rootViewController = initialViewController
// Sets our window up in front
self.window?.makeKeyAndVisible()
return true
}
Now, for example, many times we do something like this when we want to either drive the user to a login screen or to a initial setup screenl or back to the mainScreen of the app, etc. If you want to do something like that too, you can use this point as a fork-in-the-road for that.
Think about it. You could have a value stored in NSUserDefaults for instance that held a userLoggedIn Boolean and if userLoggedIn == false { use this storyboard & initialViewController... } else { use this storyboard & initialViewController... }
Well all the answers above/below are producing a warning about no entry point in storyboard.
If you want to have 2 (or more) entry view controllers that depend on some condition (say conditionVariable) then what you should do is:
In your Main.storyboard create UINavigationController without rootViewController, set it as entry point
Create 2 (or more) "Show" segues into view controllers, assign them some id, say id1 and id2
Use next code:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let navigationController = window!.rootViewController! as! UINavigationController
navigationController.performSegueWithIdentifier(conditionVariable ? "id1" : "id2")
return true
}
Hope this helps.
Here is complete Solution in Swift 4
implement this in didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let isLogin = UserDefaults.standard.bool(forKey: "Islogin")
if isLogin{
self.NextViewController(storybordid: "OtherViewController")
}else{
self.NextViewController(storybordid: "LoginViewController")
}
}
write this Function any where inside Appdelegate.swift
func NextViewController(storybordid:String)
{
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let exampleVC = storyBoard.instantiateViewController(withIdentifier:storybordid )
// self.present(exampleVC, animated: true)
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = exampleVC
self.window?.makeKeyAndVisible()
}
Just in case you want 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.
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("YOUR_VC_IDENTIFIER") as! YourViewController
appDelegate.window?.rootViewController = yourVC
appDelegate.window?.makeKeyAndVisible()
For swift 4.0.
In your AppDelegate.swift file in didfinishedlaunchingWithOptions method, put the following code.
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let rootVC = MainViewController() // your custom viewController. You can instantiate using nib too. UIViewController(nib name, bundle)
//let rootVC = UIViewController(nibName: "MainViewController", bundle: nil) //or MainViewController()
let navController = UINavigationController(rootViewController: rootVC) // Integrate navigation controller programmatically if you want
window?.rootViewController = navController
return true
}
Hope it will work just fine.
Swift 5 & Xcode 11
So in xCode 11 the window solution is no longer valid inside of appDelegate. They moved this to the SceneDelgate. You can find this in the SceneDelgate.swift file.
You will notice it now has a var window: UIWindow? present.
In my situation I was using a TabBarController from a storyboard and wanted to set it as the rootViewController.
This is my code:
sceneDelegate.swift
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).
self.window = self.window ?? UIWindow()//#JA- If this scene's self.window is nil then set a new UIWindow object to it.
//#Grab the storyboard and ensure that the tab bar controller is reinstantiated with the details below.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "tabBarController") as! UITabBarController
for child in tabBarController.viewControllers ?? [] {
if let top = child as? StateControllerProtocol {
print("State Controller Passed To:")
print(child.title!)
top.setState(state: stateController)
}
}
self.window!.rootViewController = tabBarController //Set the rootViewController to our modified version with the StateController instances
self.window!.makeKeyAndVisible()
print("Finished scene setting code")
guard let _ = (scene as? UIWindowScene) else { return }
}
Make sure to add this to the correct scene method as I did here. Note that you will need to set the identifier name for the tabBarController or viewController you are using in the storyboard.
In my case I was doing this to set a stateController to keep track of shared variables amongst the tab views. If you wish to do this same thing add the following code...
StateController.swift
import Foundation
struct tdfvars{
var rbe:Double = 1.4
var t1half:Double = 1.5
var alphaBetaLate:Double = 3.0
var alphaBetaAcute:Double = 10.0
var totalDose:Double = 6000.00
var dosePerFraction:Double = 200.0
var numOfFractions:Double = 30
var totalTime:Double = 168
var ldrDose:Double = 8500.0
}
//#JA - Protocol that view controllers should have that defines that it should have a function to setState
protocol StateControllerProtocol {
func setState(state: StateController)
}
class StateController {
var tdfvariables:tdfvars = tdfvars()
}
Note: Just use your own variables or whatever you are trying to keep track of instead, I just listed mine as an example in tdfvariables struct.
In each view of the TabController add the following member variable.
class SettingsViewController: UIViewController {
var stateController: StateController?
.... }
Then in those same files add the following:
extension SettingsViewController: StateControllerProtocol {
func setState(state: StateController) {
self.stateController = state
}
}
What this does is allows you to avoid the singleton approach to passing variables between the views. This allows easily for the dependency injection model which is much better long run then the singleton approach.
Swift 5.3 + and iOS 13.0 +
Set your initial ViewController in "SceneDelegate.swift" // Only
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
setInitialViewController()
window?.makeKeyAndVisible()
}
func setInitialViewController() {
// Set Story board Controller
/*
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "ViewController")
*/
// Set Custom Xib
let vc = FrontVC(nibName: "FrontViewController", bundle: nil)
// Navigation Controller
let nav = UINavigationController(rootViewController: vc)
nav.isNavigationBarHidden = true
window?.rootViewController = nav
}
iOS 13+
In the SceneDelegate:
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options
connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
let vc = UIViewController() //Instead of UIViewController() we initilise our initial viewController
window?.rootViewController = vc
window?.makeKeyAndVisible()
}
I worked out a solution on Xcode 6.4 in swift.
// I saved the credentials on a click event to phone memory
#IBAction func gotobidderpage(sender: AnyObject) {
if (usernamestring == "bidder" && passwordstring == "day303")
{
rolltype = "1"
NSUserDefaults.standardUserDefaults().setObject(usernamestring, forKey: "username")
NSUserDefaults.standardUserDefaults().setObject(passwordstring, forKey: "password")
NSUserDefaults.standardUserDefaults().setObject(rolltype, forKey: "roll")
self.performSegueWithIdentifier("seguetobidderpage", sender: self)
}
// Retained saved credentials in app delegate.swift and performed navigation after condition check
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let usernamestring = NSUserDefaults.standardUserDefaults().stringForKey("username")
let passwordstring = NSUserDefaults.standardUserDefaults().stringForKey("password")
let rolltypestring = NSUserDefaults.standardUserDefaults().stringForKey("roll")
if (usernamestring == "bidder" && passwordstring == "day303" && rolltypestring == "1")
{
// Access the storyboard and fetch an instance of the view controller
var storyboard = UIStoryboard(name: "Main", bundle: nil)
var viewController: BidderPage = storyboard.instantiateViewControllerWithIdentifier("bidderpageID") as! BidderPage
// Then push that view controller onto the navigation stack
var rootViewController = self.window!.rootViewController as! UINavigationController
rootViewController.pushViewController(viewController, animated: true)
}
// Override point for customization after application launch.
return true
}
Hope it helps !
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
}
Open a viewcontroller with SWRevealViewController From App delegate.
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "StoryboardName", bundle: nil)
let swrevealviewcontroller:SWRevealViewController = storyboard.instantiateInitialViewController() as! SWRevealViewController
self.window?.rootViewController = swrevealviewcontroller
self.window?.makeKeyAndVisible()
For Swift 5+
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
let submodules = (
home: HomeRouter.createModule(),
search: SearchRouter.createModule(),
exoplanets: ExoplanetsRouter.createModule()
)
let tabBarController = TabBarModuleBuilder.build(usingSubmodules: submodules)
window.rootViewController = tabBarController
self.window = window
window.makeKeyAndVisible()
}
}
I find this answer helpful and works perfectly for my case when i needed to change the rootviewcontroller if my app user already exist in the keychain or userdefault.
https://stackoverflow.com/a/58413582/6596443

Resources