I would like to know which is the best way to do this and how to implement it:
When the app runs, it checks if there's a value in user defaults
NSUserDefaults.standardUserDefaults().valueForKey("uid") == nil If the value is nil, I would like the app to redirect to a view called LoginViewController, and if not nil, go to MainViewController. Both clases are UIViewController.
I was thinking in create a new RedirectViewController as initial View Controller, and check it there, but it doesn't work, it doesn't redirects:
class RedirectOnStart: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if NSUserDefaults.standardUserDefaults().valueForKey("uid") == nil {
self.performSegueWithIdentifier("loginRegisterSegue", sender: nil)
} else {
self.performSegueWithIdentifier("mainViewSegue", sender: nil)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "loginRegisterSegue" {
let nav = segue.destinationViewController as! LoginRegisterViewController
}
if segue.identifier == "mainViewSegue" {
let nav = segue.destinationViewController as! ViewController
}
}
}
If your scenario starts with "when the app runs" you should consider working in the AppDelegate's didFinishLaunchingWithOptions directly.
For example:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow()
if NSUserDefaults.standardUserDefaults().valueForKey("uid") == nil {
self.window?.rootViewController = LoginController()
} else {
self.window?.rootViewController = MainController()
}
self.window?.makeKeyAndVisible()
return true
}
Found that the above answer is written for Objective-C not Swift; currently written it won't load up the actual view controller you want. Below code will work within 'didFinishLaunchingWithOptions".
make sure you have a userdefault (in my case "Username") for the statement to check for. If it find it's empty; that'll direct you to "SignUpVC", if it's not empty, it'll direct you to "LoginVC".
you'll need to ensure you have set your identifiers for your View Controllers on your storyboard (in my case, 'Main').
after this, make sure you have some sort of method setup to go from Login/Signup to the next set of screens, such as a segue.
Hope this helps someone out there, Have a great day.
Swift 3:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.window = UIWindow()
if UserDefaults.standard.value(forKey: "Username") == nil {
let signupViewCon = storyboard.instantiateViewController(withIdentifier: "SignUpVC")
self.window?.rootViewController = signupViewCon
} else {
let loginViewCon = storyboard.instantiateViewController(withIdentifier: "LoginVC")
self.window?.rootViewController = loginViewCon
}
self.window?.makeKeyAndVisible()
return true
}
Related
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
}
This question already has answers here:
set initial viewcontroller in appdelegate - swift
(24 answers)
Closed 5 years ago.
I am trying to add a disclaimerViewController to my application as the initial viewController, which, if accepted will lead the user tot he entryViewController, and if not, will not allow the user to use the application. However, I want to to be that if the user accepts the disclaimer, any time after he opens the application he won't be presented with the disclaimerViewControleler but with the entryViewController.
I know that it has something do to with editing the AppDelegate.swift file, but am unsure of were to start.
You need to save user choice in UserDefaults
The code below is using Swift 3
If you don't want to load entryViewController then In the AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//retrieve values from UserDefaults
//for the first time it will be false, because it was not set earlier
let isAccepted = UserDefaults.standard.bool(forKey: "isAccepted")
if isAccepted == false {
//present your disclaimer here
}else{
//show entryViewController
}
return true
}
Or you can load entryViewController and present disclaimer instantly, then in your entryViewController:
override func viewDidLoad() {
super.viewDidLoad()
//retrieve values from UserDefaults
//for the first time it will be false, because it was not set earlier
let isAccepted = UserDefaults.standard.bool(forKey: "isAccepted")
if isAccepted == false {
//present your disclaimer here
}
}
In the DisclaimerVC:
#IBAction func accept(_ sender: UIButton){
//it can be another action in your controller
//but anyway, you should save user choice after that
UserDefaults.standard.set(true, forKey: "isAccepted")
//add code here to dismiss disclaimer
}
The way I would go about doing this is by setting your disclaimerViewController to the initial view controller in your storyboard file.
In the swift file check to see if the user has previously accepted the disclaimer in the viewDidLoad method, if they haven't, allow the code to function normally and display the screen, if they have push the user on to your entryViewController
If you want to set your initial view controller in the AppDelgate and not in the storyboard, here is a useful link: set initial viewcontroller in appdelegate - swift
To transition to a new viewcontroller in swift, here is a useful link: Switching view controllers in swift
The smoothest way to implement this is to switch the views programmatically.
Make sure to set the restoration ids for your ViewControllers in the StoryBoard.
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var mainViewController: ViewController?
var acceptViewController: AcceptViewController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
mainViewController = mainStoryboard.instantiateViewController(withIdentifier: "MainView") as? ViewController
acceptViewController = mainStoryboard.instantiateViewController(withIdentifier: "AcceptView") as? AcceptViewController
if mainViewController == nil {
print("mainViewController is nil")
}
if acceptViewController == nil {
print("acceptViewController is nil")
}
let isAccepted = UserDefaults.standard.bool(forKey: "isAccepted")
if isAccepted == false {
switchToAcceptViewController()
} else {
switchToMainViewController()
}
return true
}
func switchToMainViewController() {
//mainViewController?.selectedIndex = 0 // only needed if the main view controller is a tab view
self.window?.rootViewController = mainViewController
self.window?.makeKeyAndVisible()
}
func switchToAcceptViewController() {
//mainViewController?.selectedIndex = 0 // only needed if the main view controller is a tab view
self.window?.rootViewController = acceptViewController
self.window?.makeKeyAndVisible()
}
}
AcceptViewController
class AcceptViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func acceptAction(_ sender: Any) {
UserDefaults.standard.set(true, forKey: "isAccepted")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.switchToMainViewController()
}
}
You can get the full project here: https://github.com/ryantxr/legendary-fiesta
I am trying to perform a segue on successful login in swift 3. Once my web service returns success message I want to perform segue. I am trying the same in the following manner:
DispatchQueue.main.sync(execute: {
print("Login successful")
self.performSegue(withIdentifier: "goToTimerPage", sender: self)
})
My log is printing fine.
Please help me with this. I am new to web services.
use like this
DispatchQueue.main.sync(execute: {
print("Login successful")
self.performSegue(withIdentifier: "goToTimerPage", sender: self)
})
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "goToTimerPage" {
//present your view controller or do some code
}
Simple way for navigation.
Setup your didFinishLaunchingWithOptions like this way.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let storyboard :UIStoryboard
if UIDevice.currentDevice().userInterfaceIdiom == .Pad{
storyboard = UIStoryboard(name: "Main_iPad", bundle: nil)
}
else{
storyboard = UIStoryboard(name: "Main", bundle: nil)
}
let navigationController:UINavigationController = storyboard.instantiateInitialViewController() as! UINavigationController
let objLoginViewController:UIViewController = storyboard.instantiateViewControllerWithIdentifier("ID_LoginViewController") as! LoginViewController
navigationController.viewControllers = [objLoginViewController]
if self.window != nil {
self.window!.rootViewController = navigationController
}
return true
}
Call this function once get successful response.
self.redirectToNewViewcontroller()
Code for redirectToNewViewcontroller function
func redirectToNewViewcontroller()
{
let objNewViewController = self.storyboard?.instantiateViewControllerWithIdentifier("ID_NewViewController") as? NewViewController
self.navigationController?.pushViewController(objNewViewController!, animated: true)
}
simply make sure you embed your view controller in a navigation controller
the source view controller not the destination view controller
I use firebase for authentication. Once user logs in, i want move to home screen with Tab controller.
App Delegate Function
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool
{
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.makeKeyAndVisible()
navToSignin()
return true
}
func navToHome()
{
print("navToHome")
let customTab = CustomTabBar()
window?.rootViewController = customTab
}
func navToSignin()
{
let firstPage = SigninNewVC()
window?.rootViewController = firstPage
}
SigninNewVC
override func viewWillAppear(animated: Bool)
{
super.viewWillAppear(animated)
if FIRAuth.auth()?.currentUser?.uid != nil
{
if let appDel = UIApplication.sharedApplication().delegate as? AppDelegate
{
print("viewWillAppear")
appDel.navToHome()
//This func gets called but still does not navigate to Home VC
}
}
}
private func fbSignin(token: String)
{
FIRAuth.auth()?.signInWithCustomToken(token) { (user, error) in
if error == nil
{
if user != nil
{
if let appDel = UIApplication.sharedApplication().delegate as? AppDelegate
{
JulehHUD.hideProgressHUD(self.view!)
appDel.jumpToHome()
//This part works fine when i login it navigates to Home Screen
}
}
}
else
{
print("Error:\n\(error)\n")
}
}
}
When i login for the first time it works fine I am able to Navigate to Home screen. But if i relaunch the App i not able to navigate to the home screen. It stays in the SigninNewVC though the print Statements print("viewWillAppear")& print("navToHome") are executed. Not sure what i am doing wrong. Below is my Tab bar class
class CustomTabBar: UITabBarController
{
override func viewDidLoad()
{
super.viewDidLoad()
let homeController = HomeScreenVC()
let newHomeTab = UINavigationController(rootViewController: homeController)
newHomeTab.title = "Home"
viewControllers = [newHomeTab]
}
}
Kindly let me know what i am doing wrong.
I think you insantiated the VC wrongly, you should be using something like CustomTabBar(nibName: nil, bundle:nil) and add your subview in it's loadView:
Adding below code to navToHome() & navToSignin() in App Delegate fixed the issue.
window = UIWindow(frame: UIScreen.mainScreen().bounds)
window?.makeKeyAndVisible()
I am developing an iOS App that has several Tabs. So I decided my root view Controller will be a Tab Bar Controller with 2 views.
I need the user to login as soon as the application starts, so I'm trying to find out the best approach to do this.
Following other similar questions posted here I've tried this 2 approaches:
Presenting the login screen as a Modal View on top of the Tab Bar Controller
Instantiating the Login view controller
I've done this, by using a UserisLoggedIn flag in NSUserDefaults that is set every time the user logs in or logs out.
The problem I face with both approaches is that before the login screen appears there's a quick flickr of the first view in the Tab Bar.
I've tried to resolve this setting the alpha value of the Tab Bar to 0 if the user is not logged in for the modal approach, but for the instance approach it doesnt work, it still flickers before showing the login screen. Anyway, I find this solution tedious and not really elegant.
There must be a standard approach for doing this in iOS, since you have loads of apps that present first a login screen, but since I am a beginner with iOS Programming I still don't know how to do it.
Here's some code from my Tab bar controller:
1st Approach
Tab Bar Controller
override func viewDidLoad() {
super.viewDidLoad()
view.alpha = 0
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") as NSString == "loggedIn"{
view.alpha = 1.0
}
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(false)
self.showLoginView()
}
func showLoginView(){
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
self.performSegueWithIdentifier("loginView", sender: self)
}
}
Login View Controller
func updateUserLoggedInFlag() {
// Update the NSUserDefaults flag
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject("loggedIn", forKey: "userLoggedIn")
defaults.synchronize()
}
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
self.performSegueWithIdentifier("dismissLogin", sender: self)
}
2nd Approach, Creating an Instance of the Login View Controller
1st View in the Tab Bar
override func viewDidAppear(animated: Bool){
super.viewDidAppear(true)
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
let loginController: LoginViewController = self.storyboard?.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.tabBarController?.presentViewController(loginController, animated: false, completion: nil)
}
Login View Controller
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
self.dismissViewControllerAnimated(true, completion: nil)
}
OK here is what did the trick for me. I don't know if it's the right thing to do, but it seems to work. Like Joseph Duffy mentioned all I did was to set the Login view as the rootviewcontroller in the delegate, and once I was succesfully logged in, switch back to the tab bar controller as rootviewcontroller.
Code in AppDelegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
showLogin()
}
}
func showLogin() {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController = loginViewController
}
Code in LoginViewController
#IBAction func login(sender: AnyObject) {
//Do my login here...
//If login successful:
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let appDelegate: AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
self.dismissViewControllerAnimated(true, completion: nil)
appDelegate.window?.rootViewController = storyboard.instantiateViewControllerWithIdentifier("tabBarID") as TabBarController
}
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let defaults = NSUserDefaults.standardUserDefaults()
if defaults.objectForKey("userLoggedIn") == nil{
showLoginView()
}
func showLoginView(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController: LoginViewController = storyboard.instantiateViewControllerWithIdentifier("LoginViewController") as LoginViewController
self.window?.makeKeyAndVisible()
self.window?.rootViewController?.presentViewController(loginViewController, animated: true, completion: nil)
}
Take a look at a similar question's answer. The solution is to do this check in your app delegate's application:didFinishLaunchingWithOptions: method by checking if the user is logged in and loading the login view from a storyboard when necessary.
I have created a blank project, added a view controller with a storyboard identifier of loginScreen and have the following code in the app delegate:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
self.showLogin()
return true
}
func showLogin() {
//loginScreen
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginViewController = storyboard.instantiateViewControllerWithIdentifier("loginScreen") as UIViewController
if let window = self.window {
window.makeKeyAndVisible()
window.rootViewController?.presentViewController(loginViewController, animated: false, completion: nil)
}
}
This shows the login screen and the main screen is not seen.