How do I dismiss a rootViewController before presenting a new UITabBarController? - ios

I've set up a UIViewController as my rootViewController in AppDelegate, however, when a user logs in or skips it I am presenting a UITabBarController over the top.
I need to dismiss the LoginController, and set the UITabController as rootViewController instead after user logs in.
How can I go about reorganizing this?
AppDelegate()
window = UIWindow()
window?.makeKeyAndVisible()
window?.rootViewController = LoginController()
LoginController()
self.present(MainTabBarController(), animated: true, completion: nil)

you can design your code like this.
This one

It's too easy to maintain condition for user logged in or not, and then based on that status. You can navigate to your view.
You can try this way :
1.In AppDelegate you can these methods.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let isLogin = UserDefaults.standard.bool(forKey: "IS_LOGIN")
if isLogin == true {
self.goToDashboardView()
} else {
self.goToLoginView()
}
return true
}
//MARK:- ------- Global Methods -------
class func sharedInstance() -> AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
func goToLoginView() {
let sb = UIStoryboard.init(name: "Main", bundle: nil)
let loginVC = sb.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
let navVC = UINavigationController(rootViewController: loginVC) // You can skip this if you do not want to add navigation bar
self.window?.rootViewController = navVC // if you skipped above line, then you have to assign 'loginVC' here.
self.window?.makeKeyAndVisible()
}
func goToDashboardView() {
let sb = UIStoryboard.init(name: "Main", bundle: nil)
let tabbarVC = sb.instantiateViewController(withIdentifier: "MyTabBarController") as! MyTabBarController
self).window?.rootViewController = tabbarVC // if you skipped above line, then you have to assign 'loginVC' here.
self.window?.makeKeyAndVisible()
}
2.In LoginViewController, when user logged in successfully.
#IBAction func btnLoginClicked(_ sender: UIButton) {
// Your API call or other code
// If all things goes well, then login and go to dashboard
UserDefaults.standard.set(true, forKey: "IS_LOGIN")
AppDelegate.sharedInstance().goToDashboardView()
}
3.And finally, whenever and from wherever you want to log out from app, just call below code.
#IBAction func btnLogOutClicked(_ sender: UIButton) {
// Your API call or other code
// If all things goes well, then logout and go to login view
UserDefaults.standard.set(false, forKey: "IS_LOGIN")
AppDelegate.sharedInstance().goToLoginView()
}
4.And Main.storyboard should have design something like :

you do not need to present the UITabBarViewController and then dismiss the LoginViewController, you just need to reset the UITabBarViewController as a rootViewController for you app after login or skip as the following:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
// Override point for customization after application launch.
let yourTabBar = UIStoryboard(name: "YOUR_STORYBOARD_NAME", bundle: nil).instantiateViewController(withIdentifier: "YOUR_UITABBARCONTROLLER_ID")
self.window!.rootViewController = yourTabBar
self.window!.makeKeyAndVisible()
return true
}

Related

sideMenu not displayed after login

I have included kukushi side menu. I have done things according to the documentation. The screen shot with the codes in app delegate are below:
func setUpHomeVC() {
var window: UIWindow?
let storyBoard = UIStoryboard.init(name: "Dashboard", bundle: Bundle.main)
let contentViewController = storyBoard.instantiateViewController(withIdentifier: "DashboardViewController") as! DashboardViewController
let menuViewController = storyBoard.instantiateViewController(withIdentifier: "MenuViewCOntroller") as! MenuViewCOntroller
SideMenuController.preferences.basic.menuWidth = 240
SideMenuController.preferences.basic.statusBarBehavior = .hideOnMenu
SideMenuController.preferences.basic.position = .sideBySide
SideMenuController.preferences.basic.direction = .left
SideMenuController.preferences.basic.enablePanGesture = true
SideMenuController.preferences.basic.supportedOrientations = .portrait
SideMenuController.preferences.basic.shouldRespectLanguageDirection = true
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = SideMenuController(contentViewController: contentViewController,
menuViewController: menuViewController)
window?.makeKeyAndVisible()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
setUpHomeVC()
return true
}
The identifier, class and module has been added according to the documentation. After login there is dashboard which consist of menu button. On login the code is:
private func goToDashboard() {
let dashboard = UIStoryboard(name: "Dashboard", bundle: nil)
let navView = dashboard.instantiateViewController(identifier: "DashboardViewController") as DashboardViewController
present(navView,animated: false)
}
On dashboard there is a button which have click event:
#IBAction func btnMenuClicked(_ sender: Any) {
print("Menu button has been clicked")
self.sideMenuController?.revealMenu(animated: true)
}
when I click on that button the print function is called but the menu is not revealed.
Can anyone explain it. Thanks in advance.
You can setup your appDelegate like this,
func setUpHomeVC() {
let storyboard = UIStoryboard(name: "Your Login Storyboard", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "LoginVC")
self.window?.rootViewController = initialViewController
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
setUpHomeVC()
return true
}
And in your login event:
private func goToDashboard() {
self.pushVC()
}
private func pushVC() {
let storyBoard = UIStoryboard.init(name: "Dashboard", bundle: Bundle.main)
let contentViewController = storyBoard.instantiateViewController(withIdentifier: "DashboardViewController") as! DashboardViewController
let menuViewController = storyBoard.instantiateViewController(withIdentifier: "MenuViewCOntroller") as! MenuViewCOntroller
SideMenuController.preferences.basic.menuWidth = 240
SideMenuController.preferences.basic.statusBarBehavior = .hideOnMenu
SideMenuController.preferences.basic.position = .sideBySide
SideMenuController.preferences.basic.direction = .left
SideMenuController.preferences.basic.enablePanGesture = true
SideMenuController.preferences.basic.supportedOrientations = .portrait
SideMenuController.preferences.basic.shouldRespectLanguageDirection = true
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = SideMenuController(contentViewController: contentViewController,
menuViewController: menuViewController)
window?.makeKeyAndVisible()
}
Your DashboardVC should be in a navigation controller for sidemenu to present. Try pushing the controller instead of presenting it.If you have the controller in a different storyboard, you can use this function:
func pushVC(storyboardName : String, vcname : String) {
let vc = UIStoryboard.init(name: storyboardName, bundle: Bundle.main).instantiateViewController(withIdentifier: vcname)
self.navigationController?.pushViewController(vc, animated: true)
}
Also, I would suggest you learn about when to push, present, and make root view controllers as all serve different purposes.
I think your current implementation is wrong. The problem is we need to implement and push the view controllers as SideMenuControllers bundle, not separate ViewControlers
If you want to have the side menu after login, then set your login page first in your didFinishLaunchingWithOptions.
Then you can call setUpHomeVC from your loginVC.

why my nav controller is nil even after embedding navigation controller in story board and using push segue?

I have tried to read several threads on Stackoverflow, but I think that I have implemented all of them but still it doesn't work. here is my storyboard
so I hide (uncheck) the navigation bar visibility like the image below, because I want to implement my own 'navigation header' like in the image above (in the right) :
and when the back button is pressed, I use the code below:
self.navigationController?.popViewController(animated: true)
but unfortunately, after I check, the navigation controller is nil and I can't get back to previous VC.
I set some code in the app delegate like this, in order to set the navigation. if the user has already login then it will be navigated to HomeVC (main tab bar), otherwise it will be directed to login sequence like my storyboard above
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// to print Local Database Location, uncomment the line below if you want to trace the location of Realm Database / User Default
// print("Location of Realm Database: \(Realm.Configuration.defaultConfiguration.fileURL)")
checkHasLoggedInOrNot()
return true
}
}
extension AppDelegate {
// MARK: - Helper Methods
func checkHasLoggedInOrNot() {
let userHasLoggedIn = AuthService.shared.hasLoggedIn
if userHasLoggedIn {
goToMainTabBar()
} else {
goToAuthVC()
}
}
}
extension AppDelegate {
// MARK: - Navigation
func goToMainTabBar() {
let storyboard = UIStoryboard(name: StoryBoardName.Main.rawValue, bundle: nil)
let mainTabBar = storyboard.instantiateViewController(withIdentifier: MainStoryboardData.StoryBoardID.MainTabBar.rawValue)
window?.rootViewController = mainTabBar
}
func goToAuthVC() {
let storyboard = UIStoryboard(name: StoryBoardName.Auth.rawValue, bundle: nil)
let authVC = storyboard.instantiateViewController(withIdentifier: AuthStoryboardData.StoryBoardID.AuthVC.rawValue)
window?.rootViewController = authVC
}
}
maybe the problem is the code below ?
func goToAuthVC() {
let storyboard = UIStoryboard(name: StoryBoardName.Auth.rawValue, bundle: nil)
let authVC = storyboard.instantiateViewController(withIdentifier: AuthStoryboardData.StoryBoardID.AuthVC.rawValue)
window?.rootViewController = authVC
}
because it is pointed to AuthVC ? not to Navigation Controller ?
what went wrong in here ?
Push/Pop only be possible if there is Navigation stack in window.
Replace your goToAuthVC with following -
func goToAuthVC() {
let storyboard = UIStoryboard(name: StoryBoardName.Auth.rawValue, bundle: nil)
let authVC = storyboard.instantiateViewController(withIdentifier: AuthStoryboardData.StoryBoardID.AuthVC.rawValue)
let navigationController = UINavigationController(rootViewController: authVC)
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
}

How to maintain login session in ios?

I would like to know where I need to change the root view controller in the app programming. Below is my code
class NavigationViewController: UINavigationController {
var window: UIWindow?
override func viewDidLoad() {
super.viewDidLoad()
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let newRootView = storyBoard.instantiateViewController(withIdentifier: "WelcomeViewController") as! WelcomeViewController
let userStatus = UserDefaults.standard.bool(forKey: "isLoggedIn")
if userStatus {
self.window?.rootViewController = newRootView
}
}
}
I am setting the value for isLoggedIn key as true when user logged in and false when the user logged out so that I can retrieve the value in this navigation controller subclass, based on that I can choose the root view controller. But its not working fine it remains the same whenever I am launching the app I am getting the login page only though I already logged in, also please don't suggest me to change the root view controller inside of didfinishlaunchingwithoptions method. Could someone help me to solve it? Thanks in advance.
If I understand correctly the goal of your code, you want to boot directly on WelcomeViewController if the user is already logged in.
You could try to create a custom segue called ReplaceSegue and set this ReplaceSegue to the segue linking the NavigationViewController and the ViewController.
And then you can change the destination of your segue.
class ReplaceSegue: UIStoryboardSegue {
override func perform() {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let newRootView = storyBoard.instantiateViewController(withIdentifier: "WelcomeViewController") as! WelcomeViewController
sourceViewController.navigationController?.setViewControllers([newRootView], animated: true)
}
}
First set user login bool true in NSUserDefults. when User is login Successfully.
UserDefaults.standard.set(true, forKey: "USERISLOGIN")
Now Open Appdelegate.swift -> didFinishLaunchingWithOptions Method:-
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if(UserDefaults.standard.bool(forKey: "USERISLOGIN")){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let objLogoutVC = storyboard.instantiateViewController(withIdentifier: "LogoutVC") as! LogoutVC
let navigationController = UINavigationController(rootViewController: objLogoutVC)
navigationController.navigationBar.isTranslucent = false
navigationController.navigationBar.isHidden = true
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
return true
}
Let me know if you needed any thing more.

Dismissing initial ViewController

I am developing an app using swift 3 . I launch a tutorial like view controller on the first launch of my app and close it using a button .But the inital view controller does not get dismissed even when i click the close button. I know the question sounds familiar but i am unable to get a correct solution for it .
Here's the code of the the AppDelegate
import UserNotifications
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application:
UIApplication,didFinishLaunchingWithOptions launchOptions: [
UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
let launchedBefore = UserDefaults.standard.bool(forKey: "launchedBefore")
if launchedBefore {
print("This is not the first Launch")
} else
{
print("First Launch, setting UserDefaults")
UserDefaults.standard.set(true, forKey: "launchedBefore")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let initiaView = storyBoard.instantiateViewController(withIdentifier: "FirstLaunchViewController")
self.window?.rootViewController = initiaView
self.window?.makeKeyAndVisible()
}
return true
}
Here's my code from the initialViewController
class FirstLaunchViewController:UIViewController
{
override func viewDidLoad() {
}
#IBAction func doneButtonTapped(_ sender: Any)
{
_ = navigationController?.popViewController(animated:true)
}
}
Try this
let rootViewController = self.window?.rootViewController // this is your initial viewcontroller set initial viewcontroller in storyboard
let initiaView = storyBoard.instantiateViewController(withIdentifier: "FirstLaunchViewController")
rootViewController.pushViewController(initiaView, animated: true)
Try setting the view controller as root view controller for window which you want to show after dismissing the initial view controller. Present the initial view controller from window root view controller

How to change the initial view controller through swift code

I'm developing an app with initial view controller as "Navigation controller". The app contains 2 ideas to implement.
1) From the RegisterViewController, User has to register the mobile no with verification //from sms or call, After verified it enters into HomeViewController( Condition: when the user install the app for the 1st time it shows the RegisterViewController)
2) If the app is already get installed into the iPhone and the user also register the mobile no, then the user opens the same app now the initialViewController must be the HomeViewController
How can I achieve this idea through swift code?
Implement this logic in your appdelegate class:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let isRegistered = NSUserDefaults.standardUserDefaults().boolForKey("ALLREADY_REGISTER")
if isRegistered == true{
// implement home view controller
let homeViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("HomeVC") as! HomeViewController
self.window?.rootViewController = homeViewController
self.window?.makeKeyAndVisible()
}else{
// implement register view controller
let registerViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("RegisterVC") as! RegisterViewController
self.window?.rootViewController = registerViewController
self.window?.makeKeyAndVisible()
}
return true
}
Then when first time register completed successfully then set bool variable true for the key ALLREADY_REGISTER
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "ALLREADY_REGISTER")`
do like
var viewController: UIViewController!
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
var storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if NSUserDefaults.standardUserDefaults().objectForKey("notRegistered") == nil
{
viewController = storyboard.instantiateViewControllerWithIdentifier("RegisterViewController")
}
else {
if NSUserDefaults.standardUserDefaults().objectForKey("notRegistered") as! String == "registred"
{
viewController = storyboard.instantiateViewControllerWithIdentifier("HomeViewController")
}
else
{
viewController = storyboard.instantiateViewControllerWithIdentifier("RegisterViewController")
}
// if you want to create the UINavigationController use this
let nav = UINavigationController(rootViewController: viewController)
self.window!.rootViewController = nav
else directly access use this
self.window!.rootViewController = viewController
self.window.makeKeyAndVisible()
// Override point for customization after application launch.
return true
}
on registration page after the success save like
//Save
NSUserDefaults.standardUserDefaults().setObject("registred", forKey: "notRegistered")
you have to change rootViewController instead of initialViewController. when user verified and enters into HomeViewController store flag in NSUserDefaults.then every time in AppDelegate didFinishLaunchingWithOptions check user is already entered in HomeViewController using NSUserDefaults.
let appdelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var homeViewController = mainStoryboard.instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
let nav = UINavigationController(rootViewController: homeViewController)
appdelegate.window!.rootViewController = nav

Resources