I am relatively new to Swift and I don't have much experience with the events and functions. After investigating a little I started working on a login screen on an existing app that didn't have it before. Here's what I decided to do.
My flow goes in this order:
Login screen
After successful login I save the session info
After login screen I show the main screen using a segue
If I close and reopen the app, my login screen is still the start screen, but inside viewDidAppear I have a session check and if the session exists I perform the segue to show the main controller.
I've seen that users do this the other way around - showing the main screen first and if there's no login session they cover it with the login screen or basically show the login screen first.
In my way of doing this, what I don't like is that the login screen always appears, although to be honest it does the job for this app in specific.
Is there a way to do this without the login screen appearing when there's a session? How is this ideally done in terms of order: login screen first or login screen second? And also, what is better to use, a navigation controller for the changes or segues are enough?
many here say is not recomended doing this way but i'll use appDelegate for this, in didFinishLaunchingWithOptions
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
if requestManager.instance.token != nil {
if requestManager.instance.user.birthDate != nil && requestManager.instance.user.iscomplete() {
print("GOING TO TABBARVC")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "TabBarVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}else if requestManager.instance.user.birthDate != nil && !requestManager.instance.user.iscomplete(){
print("GOING TO DATANC")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "TabBarVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}else{
print("GOING TO REGISTER")
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "register")
//loginRequest.instance.delegate = initialViewController as profileViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
}
so what i check here is for token saved in userdefault. could be checked from keycahin is it's critical, and depeding on what is found may show one or another screen, the last case is just in case where no data at all going to register or login screen.
so you could check for session is there is a session amke window show the main screen no session go to login screen
just like this in code:
if sesion != nil {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "MainVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}else{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "loginVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
where MainVC is te id in the storyBoard for the mainViewcontroller and loginVC is the storyboard Idetntifier for loginViewController.
Related
I have successfully configured google sign in my iOS App using Firebase.
After a successful login, I need to make the UIViewController move to HomeViewController.
The AppDelegate class has "didSignInFor" method in which I have added the following code
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "HomeVC")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
HomeVC is a storyboard id of HomeViewController and restoration id is also same.
But still, it doesn't take me to HomeViewController.
I have referred this stack overflow posts.
Opening view controller from app delegate using swift
Please tell me where I am going wrong. I have referred this video for building the app.
https://www.youtube.com/watch?v=20Qlho0G3YQ
Here's my AppDelegate.swift file https://pastebin.com/WfzhYAKH
Try:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "HomeVC")
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
This works for me.
Please comment if you have any questions. Happy to Help!
I am new to swift but I have implemented FCM but I am having an issue. When I click the notification it loads the NotificationsViewController with the following code.
let sb = UIStoryboard(name: "Main", bundle: nil)
let otherVC = sb.instantiateViewController(withIdentifier: "NotificationsViewController") as! NotificationsViewController
self.window?.rootViewController = otherVC;
Once the NotificationsViewController is loaded I use the following code in on the back button to reassign the root view back to the normal ViewController.
let mainStoryBoard = UIStoryboard(name: "Main", bundle: nil)
let redViewController = mainStoryBoard.instantiateViewController(withIdentifier: "splashScreen") as! ViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.window?.rootViewController = redViewController
Once I am on the splashScreen it should show a quick image and then move on to the main dashboard using this code.
let vw = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DashboardViewController") as! DashboardViewController
self.navigationController?.pushViewController(vw, animated: true)
The problem I am having is the splashScreen code is not working when the app loads it from NotificationsViewController, it just hangs on that VC, but if I load the splashScreen without reassigning the root view it works.
So is there some other way I should be doing this? I just want to take the user to the NotificationsViewController when they click the notification and then back to the main part of the app when they click a back button.
If you just need to show the NotificationViewController, you just present it in fullscreen. You can set it by vc.modalPresentationStyle = .fullScreen. Then to go back to the main app, you just need to dismiss it. :)
I was wondering where NSUserDefaults is writing all the stored data to: to the app memory or to the device the app is running on? In the latter case, I guess I should be able to retrieve stored data from NSUserDefaults even if the app has been completely shut down, right? Basically what I'm trying to do: at runtime I want to check whether or not the user was logged in when he/she shut down the app (which I store in NSUserDefaults as a Boolean at the moment a user logs in or logs out), and if the user was logged in, I want to set a different root view controller from the original root view controller a user would see if the app was opened for the first time. I've tried a lot of different things, but nothing seems to work when I test it on my device. Is NSUserDefaults the best approach to do this (if so, then how?) or are there better alternatives to do this?
When using 'NSUserDefaults' for something simple like this it will work well for what you are trying to achieve.
This is the code you would place in your AppDelegate that will handle sending the user to the correct view based on the value.
Swift 2
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let logonStatus = NSUserDefaults.boolForKey("LogonStatus")
if logonStatus {
print("User logged in.")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("navController") as! UINavigationController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
} else {
print("User not Logged in.")
self.window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewControllerWithIdentifier("loginViewController") as UIViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
return true
}
Then in your logout or logon viewController or the code to perform the logout or logon you would just need to make sure to set the 'NSUsersDefaults' value.
NSUserDefaults.setBool(true, forKey: "logonStatus") // Logged On
NSUserDefaults.setBool(false, forKey: "logonStatus") // Logged Off
Swift 3
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let logonStatus = UserDefaults.standard.bool(forKey: "LogonStatus")
if logonStatus {
print("User logged in.")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "navController") as! UINavigationController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
} else {
print("User not Logged in.")
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "loginViewController") as UIViewController
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
return true
}
Set 'UserDefaults'
UserDefaults.standard.set(true, forKey: "LogonStatus")
You've got a few questions here. NSUserDefaults is persistent across app launches, per this other answer on StackOverflow: Data persistence through NSUserDefaults. However, once you delete the app, you will lose the data.
In terms of programming for a root view controller, I would say yeah, if you want to show the login root view controller, that's a pretty strong case for storing login persistence in NSUserDefaults. Just don't store their login directly in the defaults of course :)
One thing I would note is that it quickly gets hard to reason about view hierarchy and you can introduce pretty nasty bugs if the root view controller is changing. Like, once the user logs in, what do you do with the old root view controller? Instead of what you describe, I'd keep the same root view controller, but present a modal for login over the top of the root if a login is needed. Simpler logic and your app will be more stable.
I have implemented a side drawer in my application which required me to set the root view controller in my application delegate. i am now working on a login screen. to access the login screen i had to comment out where i set the root view controller. How can i set the root view controller once the user has logged in?
Below is my app delegate(or part of it)
AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let centerViewController = mainStoryboard.instantiateViewControllerWithIdentifier("ViewController") as!ViewController
let drawerViewController = mainStoryboard.instantiateViewControllerWithIdentifier("DrawerViewController") as!DrawerViewController
let leftSideNav = UINavigationController(rootViewController: drawerViewController)
let centerNav = UINavigationController(rootViewController: centerViewController)
centerContainer = MMDrawerController(centerViewController: centerNav, leftDrawerViewController: leftSideNav)
centerContainer!.openDrawerGestureModeMask = MMOpenDrawerGestureMode.PanningCenterView;
centerContainer!.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.PanningCenterView;
//window!.rootViewController = centerContainer
window!.makeKeyAndVisible()
return FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: launchOptions)
}
i have a method to handle the segue after successful login but don't know how to set the root controller out side the delegate.
in summary the navigation works if i uncomment the //window!.rootViewController = centerContainer line but then cant access the login view
You can swap the root view controller dynamically:
self.view.window!.rootViewController = newVc
A simple example can be found here: https://stackoverflow.com/a/34951197/218152.
A complete example can be found here: https://stackoverflow.com/a/32109767/218152.
Swapping the rootViewController is a one time operation: no back button, no animation.
To change rootViewController after login screen
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
UIApplication.shared.windows.first?.rootViewController = viewController
UIApplication.shared.windows.first?.makeKeyAndVisible()
Make sure you have set 'HomeViewController' in storyboard as Storyboard ID of HomeViewController
I'm having some troubles with revealViewController in Xcode 7.2 and iOS 9.2.
My app starts with a view controller embedded in a navigation controller to perform a login.
After login, or if the login token is present, I jump to another view controller embedded in a navigation controller with the following code:
let homePage = self.storyboard?.instantiateViewControllerWithIdentifier("HomeViewController") as! HomeViewController
let homePageNav = UINavigationController(rootViewController: homePage)
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.window?.rootViewController = homePageNav
In this home view controller I would like to have a left navigation menu with SWRealViewController.
I had the SWRealViewController view linked with sw_front to my home navigation controller, and the following code:
if (self.revealViewController() != nil) {
self.menuButton.target = self.revealViewController()
self.menuButton.action = "revealToggle:"
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
But self.revealViewController() always returns nil, so it does not work.
I think I lost the revealViewController somewhere (maybe when I jump from the first navigation controller to the second) but I do not know what to do.
The most convenient to be a reason for the revealViewController to be nil
is you didn't connect segues correctly in stroyboard.
See this tutorial it's quite easy to follow.
Update
If in your case you just need to open a login vc if the user is not logged in you may do like this:
in AppDelegate
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
var rootVCStoryboardId = userIsLoggedin ? "SWRevealViewController" : "LoginViewController"
self.window?.rootViewController = UIStoryboard(name: Storyboards.main, bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier(rootVCStoryboardId)
Where SWRevealViewController is the stroyboard id for SWRevealViewController and LoginViewController is the storyboard id for your login view controller(or its navigation controller if exists).
In case someone is wondering how to do a manual segue, this is what worked for me at the end.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let sw = storyboard.instantiateViewControllerWithIdentifier("SWRevealViewController") as! SWRevealViewController
self.view.window?.rootViewController = sw
let destinationController = self.storyboard?.instantiateViewControllerWithIdentifier("StoryboardID") as! NameOfViewController
let navigationController = UINavigationController(rootViewController: destinationController)
sw.pushFrontViewController(navigationController, animated: true)
Incase you are skipping login scene based on the current user information, then make sure to instantiate the storyboard with SWRevealViewController. See below code for reference:
if User.currentUser != nil {
//There is a current user
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("SWRevealViewController")
window?.rootViewController = vc
}
else{
//No current user
}