I am having trouble launching a tab bar controller from App Delegate. However, the controller is called correctly from a different view controller, so I know it's working. This is the code I used in the view controller:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
self.window = UIWindow(frame: UIScreen.main.bounds)
let tabBarController = self.storyboard?.instantiateViewController(identifier: Constants.Storyboard.tabBarController)
self.view.window?.rootViewController = tabBarController
self.view.window?.makeKeyAndVisible()
While that worked for the view controller, that didn't work for App Delegate, so after researching I found the following:
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
self.window = UIWindow(frame: UIScreen.main.bounds)
let tabBarController = storyBoard.instantiateViewController(withIdentifier: Constants.Storyboard.tabBarController)
self.window?.rootViewController = tabBarController
self.window?.makeKeyAndVisible()
That didn't work either. Any ideas on what I'm doing wrong? If it matters, please note the tab bar controller doesn't have its own class, I designed it in Storyboard.
Thanks for any help.
I think you should move your code to the SceneDelegate and do some changes concerning the initializiation of window.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyBoard.instantiateViewController(withIdentifier: Constants.Storyboard.tabBarController)
window = UIWindow(windowScene: windowScene)
self.window?.rootViewController = tabBarController
self.window?.makeKeyAndVisible()
}
Related
I had a working program consisting basically of a table view controller embedded in a navigation controller, and I decided to try to get rid to some mysterious/obnoxious warnings that first appeared in iOS 16 ("UINavigationBar decoded as unlocked for UINavigationController, or navigationBar delegate set up incorrectly"). Following online suggestions, I got rid of the navigation controller on the storyboard, and added some code to
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window?.windowScene = windowScene
window?.makeKeyAndVisible()
// ViewController: UITableViewController is my VC class
let viewController = ViewController()
let navViewController = UINavigationController(rootViewController: viewController)
window?.rootViewController = navViewController
}
to embed it programmatically. The program would then crash with a message that stating that it could not deque a cell with identifier "itemCell", and "must register a nib or a class for the identifier or connect a prototype cell in a storyboard". I solved that by adding the line
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "itemCell")
in ViewDidLoad but I don't understand why this was necessary, since the identifier for the prototype cell is still there in the storyboard, just as it was before. Can someone illuminate me? Thanks.
This:
let viewController = ViewController()
let navViewController = UINavigationController(rootViewController: viewController)
window?.rootViewController = navViewController
won't give you what you want.
In Storyboard, you have to give ViewController a Storyboard ID (such as "FirstViewController"), then instantiate it via code:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "FirstViewController")
let navViewController = UINavigationController(rootViewController: initialViewController)
Edit
Assuming the view controller we ID as "FirstViewController" in Storyboard is a table view controller, and we want to load it as the "root" controller for a navigation controller, the full code block would be:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window?.windowScene = windowScene
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "FirstViewController")
let navViewController = UINavigationController(rootViewController: initialViewController)
window?.rootViewController = navViewController
window?.makeKeyAndVisible()
}
i have a button in viewcontroller which navigates to editPage viewcontrooler
i want to use pushNavigation
i did below code in button action method
#IBAction func editBtn(_ sender: Any) {
let storyBoard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let newViewController = storyBoard.instantiateViewController(withIdentifier: "editProfile") as! editProfile
let navigation = UINavigationController(rootViewController: newViewController)
self.navigationController?.pushViewController(navigation, animated: true)
}
but when i click on button it dosent navigate
i dont have navigation controler in storyboard.......
i dont want to present view controler
Looks like you are setting your viewController as initail View Controller from storyboard but do not embed this in navigation controller , either embed your viewController in navigationController and set this navigation controller as initialViewController or follow this approach as you don't want to do it from storyboard:
In SceneDelegate , write :
var window: UIWindow?
and then in this method :
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 _ = (scene as? UIWindowScene) else { return }
//Setup user state
if let vc = UIStoryboard.init(name: "YOUR_STORYBOARD_NAME", bundle: nil).instantiateViewController(withIdentifier: "VIEW_CONTROLLER_IDENTIFIER") as? ViewController {
let nav = UINavigationController(rootViewController: vc)
window?.rootViewController = nav
window?.makeKeyAndVisible()
}
}
for IOS < 13, in AppDelegate.swift :
var window : UIWindow?
//MARK:- DID FINISH LAUNCHING WITH OPTIONS : CALLED EVERYTIME WHEN APPLICATION LAUNCHES
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let vc = UIStoryboard.init(name: "YOUR_STORYBOARD_NAME", bundle: nil).instantiateViewController(withIdentifier: "VIEW_CONTROLLER_IDENTIFIER") as? ViewController {
let nav = UINavigationController(rootViewController: vc)
window?.rootViewController = nav
window?.makeKeyAndVisible()
}
return true
}
This is the storyboard layout I have right now
So what I need is to check if the user is already authenticated when the app launches.
If he is not logged in set the root view controller to the navigation controller with the login and register forms.
If he is logged in set it to the tab bar view controller.
I tried a lot of different solutions but none of them worked. It just kept setting the view controller to the one marked with "Is Initial View Controller".
This is the code I tried in the AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
var viewController: UIViewController
if isAuthenticated() {
viewController = storyboard.instantiateViewController(withIdentifier: Constants.Storyboards.homeViewController) as! UITabBarController
} else {
viewController = storyboard.instantiateViewController(withIdentifier: Constants.Storyboards.authViewController) as! UINavigationController
}
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
return true
}
I can do this by pressing a button easily, but I want it to happen without the user needing to do something.
EDIT: Thanks to #LukaCefarin and #Francesco Deliro I managed to find out that the problem was. I was using XCode 11 and the rootViewController had to be set in the SceneDelegate.swift
This is what my code in the SceneDelegate.swift looks like for anyone who has a similar issue:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: scene as! UIWindowScene)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
var viewController: UIViewController;
if isAuthenticated() {
viewController = storyboard.instantiateViewController(withIdentifier: "HomeVC")
} else {
viewController = storyboard.instantiateViewController(withIdentifier: "AuthVC")
}
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
}
EDIT:
This solution and setting the window rootViewController in the AppDelegate work for versions prior to Xcode11 and iOS13. As suggested in the comments by Luka Cefarin, if you are using Xcode11 and iOS13 you have to set the window rootViewController in the SceneDelegate.swift file.
You have to remove the Main Interface and to uncheck the initial view controller in the storyboard:
Before
After
Here is the code
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "homeTBC") as! UITabBarController
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
cant figure it yet.
I have tried this code in My App for root view controller in app delegate working perfect:
As I think you are using this code in presented view controller or in presented navigation controller: Please send the scenario(Screen Shot) exact what you are doing?
var window: UIWindow?
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "TabbarVC") as! TabbarVC
self.window?.rootViewController = vc
From Apple's Documentation
When creating windows, always set the window’s initial size and
specify the screen on which it is displayed.
Add the size:
self.window = UIWindow.init(frame: UIScreen.main.bounds)
Your complete code should be like that:
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: "homeTBC") as! UITabBarController
self.window = UIWindow.init(frame: UIScreen.main.bounds)
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
I have some code to only show the first view controller in my storyboard on the first launch of the app. After that I want to skip that page and go straight to my second view on each launch. I have embedded the first view (which is connected to the second) in a navigation controller.
My issue is that after the first launch when the app goes to the second view directly it's showing the view without the navigation bar on top and I'm not sure why.
In my appdelegate:
func firstLaunchCheck(){
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore{
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialView : UIViewController = storyboard.instantiateViewController(withIdentifier: "mainScreen") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialView
self.window?.makeKeyAndVisible()
}
else{
UserDefaults.standard.set(true, forKey: "launchedBefore")
}
}
UPDATE:
I wound up just changing which view controller were embedded in the navigation controller (excluded the first one) since it didn't make sense to me to have it there. So now after the first launch it loads the navigation controller
SecondViewController is not added in UINavigationController hierarchy, to see the navigationBar on top you can push SecondViewController on firstVC if the launchedBefore is false in appDelegate
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondVC = storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
let navigationController = window.rootViewController as! UINavigationController
navigationController?.pushViewController(secondVC, animated: false)
You need to embed the second view controller i.e. "mainScreen" in UINavigationController and then make it the rootViewController of your app window.
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let navigationController = UINavigationController.init(rootViewController: storyboard.instantiateViewController(withIdentifier: "mainScreen"))
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialView
self.window?.makeKeyAndVisible()