Best practice for login for Master-Detail App - Swift - ios

I was wondering what is the best practice to implement login screen for Master-Detail application which has SplitView Controller as a root controller. I am using the appDelegate to display the login screen if the user is not logged in. However, when I want to dismiss the loginVC the app goes into blank Detail page instead of the MasterController. Would be a modal login screen better option for Master-Detail app?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as! loginViewController
self.window?.rootViewController = loginVC
return true
let splitViewController = self.window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
splitViewController.delegate = self
return true
And then in my loginVC:
#IBAction func goHome(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = storyboard.instantiateViewControllerWithIdentifier("SplitViewControllerID") as! UISplitViewController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = splitViewController
}

By changing the code of goHome function it works for me. Below is the code:
#IBAction func goHome(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = storyboard.instantiateViewController(withIdentifier: "SplitViewControllerID") as! UISplitViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = splitViewController
splitViewController.preferredDisplayMode = .allVisible
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
}

Related

Displaying View Controller within a UITabBarController programatically in Swift 5

In my app when the user logs in, they should be taken to a welcome screen, which is part of a TabBarController. But for some reason, when I run the following lines, the welcome screen (HomeScreenViewController) shows up without the TabBar navigation buttons at the bottom.
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as? HomeScreenViewController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
Inspired by another StackOverflow post, I tried this, but it didn't work either:
let homeController = self.storyboard?.instantiateViewController(identifier:Constants.Storyboard.homeViewController)
(TabBarController.currentInstance?.selectedViewController as?UINavigationController)?.pushViewController(homeController!, animated: true)
For reference, the name of my UITabBarController class is TabBarController and the identifier can be accessed via
Constants.Storyboard.tabBarCont
Thanks!
I think you can try this..
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
let tabBarController = UITabBarController()
let homeViewController = self.storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as? HomeScreenViewController
let anyOtherViewController = self.storyboard?.instantiateViewController(identifier: anyOtherViewController) as? AnyOtherViewController
homeViewController.tabBarItem = UITabBarItem(title: "Home", image: UIImage(named: "home_image"),tag: 1)
anyOtherViewController.tabBarItem = UITabBarItem(title: "Other",image:UIImage(named: "other") ,tag:2)
tabBarController.viewControllers = [homeViewController, anyOtherViewController]
window?.rootViewController = tabBarController
window?.makeKeyAndVisible()
return true
}
Use like this after login:
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let centerViewController = storyboard.instantiateViewController(withIdentifier: "tabbar") as! TabBarController
centerViewController.selectedIndex = 0
centerViewController.modalPresentationStyle = UIModalPresentationStyle.fullScreen
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if let window = UIApplication.shared.windows.first {
appDelegate.window = window
}
appDelegate.window!.rootViewController = centerViewController
self.present(centerViewController!, animated: false, completion: nil)

Going from Navigation controller to tab controller views

I am developing the iOS app. and it has some design restrictions by the client. So it looks like I have to use navigation controller and the tab controller simultaneously on different number of Viewcontrollers.
I can categories my views into 2 category.
SignUp/Login views (this is entry point at first start of app)
MainView -> This become entry point once the user is login
Now Category 1 is using NavigationView Controllers. where as Category2 is using Tab bar controllers.
What I want case 1: I want when the user install my app, he is taken to Login view which has Navigation View. Now if he already has no account he will go to "Create new account" this is the 2nd scene of the Navigation view. Now on successful creation of account, he needs to close all other navigation view controllers and need to jump to MainView which will be Tabbar view controller.
case 2: suppose user close my app after getting login, when he open it up again, now the entery point will be Mainview which has Tab bar view controller. Now I know I need to do it in App delegate method but how?
I am doing this way,and it looks like working. But I am not getting bottom tab. Why is it so?
class ViewSwitcher {
static func updateRootViewController() {
let status = UserDefaults.standard.bool(forKey: KeyConstants.IS_USER_LOGGEDIN)
var rootViewController : UIViewController?
#if DEBUG
print(status)
#endif
if (status == true) {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let mainTabBarController = mainStoryBoard.instantiateViewController(withIdentifier: "idTab1VC") as! Tab1VC
rootViewController = mainTabBarController
} else {
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let signInViewController = mainStoryBoard.instantiateViewController(withIdentifier: "idLoginVC") as! LoginVC
rootViewController = signInViewController
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = rootViewController
}
}
Any Idea how to do these cases? How to navigate programmatically by closing all the view controllers trees?
The same process I have been using for my app.
Use this code to change the rootViewController in Case2
var window: UIWindow?
var tabBarController : UITabBarController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Tabbar controller
let storyBoard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let tab1 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "tab1"))
tab1 = UITabBarItem.init(title: "Title 1", image: UIImage(named : "Image.png") , tag: 0)
let tab2 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "tab2"))
tab2 = UITabBarItem.init(title: "Title 2", image: UIImage(named : "Image.png") , tag: 1)
// Navigation controller or Login view controller
let nav1 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "nav1"))
tabBarController = UITabBarController.init()
tabBarController?.delegate = self
tabBarController?.selectedIndex = 0
tabBarController?.viewControllers = [tab1,tab2]
// The Bool value which you have to set as True after a user logged in
if UserDefaults.standard.bool(forKey: "LoggedIn"){
print("Tabbar")
self.window?.rootViewController = self.tabBarController
}else{
print("Navigation")
self.window?.rootViewController = nav1
}
return true
}
Before or After that, you have to write the same code where a user clicked on login in your loginViewController, in your case it is Case1
func loginClicked(){
UserDefaults.standard.set(true, forKey: "LoggedIn")
DispatchQueue.main.async {
let appdelegate = UIApplication.shared.delegate as! AppDelegate
// Same as above code and replace self with appDelegate without if condition and at last
appdelegate.window?.rootViewController = appdelegate.tabBarController
}
}
And after user logged out
DispatchQueue.main.async {
UserDefaults.standard.set(false, forKey: "LoggedIn")
let appdelegate = UIApplication.shared.delegate as! AppDelegate
let story = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let nav1 = UINavigationController.init(rootViewController: storyBoard.instantiateViewController(withIdentifier: "nav1"))
appdelegate.window?.rootViewController = companyNavigation
}
Use below code in app delegate didFinishWithLaunchingOptions , for main view directly.. here uid means stored value whether to check user is Active or Not.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let user_id = UserDefaults.standard.value(forKey: "uid")
{
let homeViewController = storyboard.instantiateViewController(withIdentifier: "HomeTabBarCtrlr") as! UITabBarController
let nav = UINavigationController(rootViewController: homeViewController)
self.window!.rootViewController = nav
}else{
SignUp/Login views
}
Step by step approach to this would be:
Check if user is logged in or not. For this use UserDefaults.
If user not logged in, set LoginVC as rootVC.
On Login save a key in UserDefault to signify user logged in.
Next time when user opens the app check for key and if user logged in, set TabBarVC as rootViewController.
At Logout, clear the key.
Sample Code for the above will be:
AppDelegate.swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
...........
//Check for user login and set rootViewController.
if UserDefaults.standard.bool(forKey: "login"){
self.window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
}
else{
self.window?.rootViewController = UIStoryboard(name: "Login", bundle: nil).instantiateInitialViewController()
}
return true
}
At Login Success
func loginUser(){
...
if userLoginSuccess{
UserDefaults.standard.set(true, forKey: "login")
}
}
At Logout
UserDefaults.standard.set(false, forKey: "login")
As like you know that you want to do it in Appdelgate.
When user login successfully you have to store a flag in userdefault.
In app delegate you have to check that if this flag is set or not.If set then create a navigation view controller with your initial view controller call moveToLoginWindow().
or if not then create tab bar view controller call movetoTabBarController().
func moveToLoginWindow() -> Void {
if let rootController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "LoginVC") as? LoginVC{
let navigationController = UINavigationController.init(rootViewController: rootController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
}
}
func movetoTabBarController() -> Void {
let nav2 = UINavigationController()
let second = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "secondViewController") as? SecureNotesVC
nav2.viewControllers = [second!]
nav2.tabBarItem = UITabBarItem.init(title: "Titel 2", image: UIImage.init(named: "2.png"), selectedImage: UIImage.init(named: "2_sel.png"))
let nav3 = UINavigationController()
let third = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "thirdviewController") as? FormFillsVC
nav3.viewControllers = [third!]
nav3.tabBarItem = UITabBarItem.init(title: "Titel 2", image: UIImage.init(named: "3.png"), selectedImage: UIImage.init(named: "3_sel.png"))
let nav4 = UINavigationController()
let fourth = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "fourthviewContoller") as? SettingsVC
nav4.viewControllers = [fourth!]
nav4.tabBarItem = UITabBarItem.init(title: "4", image: UIImage.init(named: "4.png"), selectedImage: UIImage.init(named: "4_sel.png"))
if #available(iOS 11.0, *) {
nav2.navigationBar.prefersLargeTitles = true
nav3.navigationBar.prefersLargeTitles = true
nav4.navigationBar.prefersLargeTitles = true
}
let tabBarController = UITabBarController()
tabBarController.viewControllers = [ nav2,nav3, nav4,nav5]
self.window!.rootViewController = tabBarController;
}

SWRevealViewController side menu is not working in swift 3

I am using SWRevealViewController for side menu functionality. Its working fine but whenever I have added the following code in didFinishLaunchingWithOptions method. side menu is not working for first time launch.
How to solve this problem??
this is my Code :
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// UserDefaults.standard.synchronize()
// IQKeyboardManager.sharedManager().enable = true
self.window = UIWindow(frame: UIScreen.main.bounds)
guard UserDefaults.standard.object(forKey: "IsFirstTime") != nil else {
UserDefaults.standard.set(true, forKey: "IsFirstTime")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "LaunchViewController") as! LaunchViewController
let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = navigationController
self.window?.makeKeyAndVisible()
return true
}
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let viewController = storyboard.instantiateViewController(withIdentifier: "SWRevealViewController") as! SWRevealViewController
// let navigationController = UINavigationController.init(rootViewController: viewController)
self.window?.rootViewController = viewController
self.window?.makeKeyAndVisible()
return true
}
Thank you
Here you are making LaunchViewController initial VC on first launch. That's why it is not working at first time.
To use SWRevealViewController you need two view controller, one is front view controller which you want to show first time and second is for drawer which maybe tableViewController that contains all other view controller. To add SWRevealViewController call openDrawer() in AppDelegate.
func openDrawer() {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let drawerVC = storyboard.instantiateViewController(withIdentifier: "idDrawerVC") as! RearVC
let dashboardVC = storyboard.instantiateViewController(withIdentifier: "idFrontVC") as! FrontVC
let frontNavigationController = UINavigationController(rootViewController: dashboardVC)
let revealViewController = SWRevealViewController(rearViewController: drawerVC, frontViewController: frontNavigationController)
revealViewController?.delegate = self
revealViewController?.view.backgroundColor = .clear
revealViewController?.modalTransitionStyle = .crossDissolve
window?.rootViewController = revealViewController
}

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

Unable to instantiate rootViewController from within AppDelegate

My onboarding process (login/signup) lives outside of the UINavigationController chain, but when the login is authenticated I call a method in the appdelegate thats supposed to instantiate the rootViewController and then push to it. I've tried two things:
The snippet above worked in appDelegate from a method that gets called when a local notification is responded to, but not in this case.
self.window?.makeKeyAndVisible()
self.window?.rootViewController?.navigationController?.popToRootViewControllerAnimated(true)
And heres another method I tried:
let rootViewController = self.window?.rootViewController
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let dashboard = mainStoryboard.instantiateViewControllerWithIdentifier("DashboardViewController") as! DashboardViewController
rootViewController!.navigationController?.popToViewController(dashboard, animated: true)
Neither of these work. What am I doing wrong?
My login view controller also live outside of my tab bar controller so this is what I did:
In the appDelegate:
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginVC = storyboard.instantiateViewControllerWithIdentifier("LoginVC") as! LoginViewController
self.window?.rootViewController = loginVC
self.window!.makeKeyAndVisible()
return true
}
then I have a method in my loginViewContoller.swift:
#IBAction func loginPushed(sender: AnyObject) {
//other stuff here
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = UITabBarController()
let first = mainStoryBoard.instantiateViewControllerWithIdentifier("firstNavController") as! UINavigationController
let second = mainStoryBoard.instantiateViewControllerWithIdentifier("secondNavController") as! UINavigationController
let third = mainStoryBoard.instantiateViewControllerWithIdentifier("thirdNavController") as! UINavigationController
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
let controllers = [first, second, third]
tabBarController.viewControllers = controllers
appDelegate.window!.rootViewController = tabBarController
appDelegate.window!.makeKeyAndVisible()
}
I think you shouldn't call the 'popToRootViewController', you can reassignment the window.rootViewController~

Resources