How to Implement Login/Logout Navigation Using Userdefaults in Swift

How I can implement Login / Logout Navigation using UserDefaults in swift?

In Xcode 11 there are 2 file while we create a new project so if you want to change rootViewController from the delegate file then you need to load that controller from the SceneDelegate.swift file.

//SceneDelegate.swift

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }

window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene

self.loadBaseController()
}

func loadBaseController() {
let storyboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
guard let window = self.window else { return }
window.makeKeyAndVisible()
if UserDefaults.standard.bool(forKey: "isLoggedIn") == false {
let loginVC: ViewController = storyboard.instantiateViewController(withIdentifier: "login") as! ViewController
self.window?.rootViewController = loginVC
} else {
let homeVC: HomeViewController = storyboard.instantiateViewController(withIdentifier: "showData") as! HomeViewController
let navigationHomeVC = UINavigationController(rootViewController: homeVC)
self.window?.rootViewController = navigationHomeVC
}
self.window?.makeKeyAndVisible()
}

How to do signin / signup and logout navigation using userdefaults in swift?

In signinVC add the following line in viewDidLoad

if UserDefaults.standard.bool(forKey: "USER_LOGIN"){
//navigate to home page
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
navigationController?.pushViewController(vc, animated: true)
}
}

Modify signupVC like following

class RegisterViewController: UIViewController {
@IBOutlet weak var firstNameTextfield: UITextField!
@IBOutlet weak var lastNameTextfield: UITextField!
@IBOutlet weak var emailTextfield: UITextField!
@IBOutlet weak var passwordTextfield: UITextField!


var userDict : Dictionary<String,UserData>?

@IBAction func registerBtnClicked(_ sender: Any) {

if firstNameTextfield.text?.isEmpty == true{
self.showAlert(title: "Registration", message: "please enter first name")

}
else if lastNameTextfield.text?.isEmpty == true{
self.showAlert(title: "Registration", message: "please enter last name")

}else if emailTextfield.text?.isEmpty == true{
self.showAlert(title: "Registration", message: "please enter email")

}else if passwordTextfield.text?.isEmpty == true{
self.showAlert(title: "Registration", message: "please enter password")

}
else{
self.userDict = UserDefaults.standard.dictionary(forKey: "UserList") as! Dictionary<String, RegisterViewController.UserData>

let userData = UserData(userName: firstNameTextfield.text, lastName: lastNameTextfield.text, email: emailTextfield.text, userPassword: passwordTextfield.text)
self.userDict[firstNameTextfield.text] = userData

UserDefaults.standard.setValue(self.userDict, forKey: "UserList")

DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
navigationController?.pushViewController(vc, animated: true)
}


}
}

struct UserData {
var userName : String
var lastName : String
var email : String
var userPassword : String
}

Finally modify loginBtnClicked method as following

@IBAction func loginBtnClicked(_ sender: Any) {

let userDict = UserDefaults.standard.dictionary(forKey: "UserList") as! Dictionary<String, UserData>

guard let usrData = userDict[userNameTextfield.text] as! UserData else {
// no user registered with this user name
return
}

if usrData.userPassword == passwordTextfield.text {
// login successfull
UserDefaults.standard.set(true, forKey: "USER_LOGIN")
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
navigationController?.pushViewController(vc, animated: true)
}

}else{
//login failed
showAlert(title: "LogIn", message: "please enter username and password")
}

}

If i logout and login then unable to login for the first time, why? in swift

I would change the login as follow:

remove everything in your SceneDelegate:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {        
guard let _ = (scene as? UIWindowScene) else { return }
}

in your SignInViewController change has follow:

override func viewDidLoad() {
super.viewDidLoad()
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
userIsloggedin()
}

func userIsloggedin(){
let userLoginStatus = UserDefaults.standard.bool(forKey: "USER_LOGIN")
if (userLoginStatus) {
self.performSegue(withIdentifier: "toHomeVC", sender: self)
}
}

@IBAction func loginBtnTapped(_ sender: UIButton) {
UserDefaults.standard.set(true, forKey: "USER_LOGIN")
self.performSegue(withIdentifier: "toHomeVC", sender: self)
}

create a segue in your storyboard named "toHomeVC". Your storyboard should look like this:

Sample Image

Sample Image

and then change your code in HomeViewController

override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true //to hide the back button
}

@IBAction func logoutBtnTapped(_ sender: UIButton) {
UserDefaults.standard.set(false, forKey: "USER_LOGIN") //logging session off
self.navigationController?.popToRootViewController(animated: true) // or false if you don't want to see the animation
}

Lastly, if you need yo use UITabarController just embed your HomeVc like so:

Sample Image

and you Storyboard should look like this:

Sample Image

If you decide to embed it the UITabBarController you must hide the back button like so:

self.tabBarController?.navigationItem.hidesBackButton = true 

iOS Login / Sign Out Implementation in Swift

The < Back button is appearing because you are doing a push segue from the login view controllers to the tab bar controller. A better flow for the app would be to have the tab bar controller be your initial view controller. Then, in its viewDidAppear method, check that the user is logged in. If the user isn't logged in, segue modally WITHOUT animation to your login view controller. This will all happen without the user noticing and will allow the storyboard setup you want

Logout button in every viewcontroller in swift 5

I've created an UILibraryFunction.swift file.

class UILibraryFunction: UIViewController {

var navBar:UINavigationBar = UINavigationBar()
var navItem = UINavigationItem(title: "SomeTitle")

var screenWidth:CGFloat = 0
var screenHeight:CGFloat = 0

var NameHeight:CGFloat = 0
var NameWidth:CGFloat = 0

override func viewDidLoad() {
super.viewDidLoad()

let screenSize: CGRect = UIScreen.main.bounds

screenWidth = screenSize.width
screenHeight = screenSize.height

NameHeight = screenHeight * 0.09
NameWidth = screenWidth
navBar = UINavigationBar(frame: CGRect(x: 0, y: 30, width: NameWidth, height: NameHeight))
self.view.addSubview(navBar)

navBar.setItems([navItem], animated: false)

}

//---- Right Bar Button -----
func rightBarButton() {
let rightBarButton = UIBarButtonItem(title: "Logout", style: UIBarButtonItem.Style.plain, target: self, action: #selector(Lge3Generell.Logout(_:)))
navItem.rightBarButtonItem = rightBarButton

}

//--- Left Bar Button -----
func leftBarButton() {

let leftBarButton = UIBarButtonItem(title: "Home", style: UIBarButtonItem.Style.done, target: self, action: #selector(self.GoToHome(_:)))
navItem.leftBarButtonItem = leftBarButton

}

//----- UI Bar Title ----
func setTitle(BarTitle:String) {
navItem = UINavigationItem(title: BarTitle)
return navBar.setItems([navItem], animated: false)
}

}

Now I call this 3 function in all of my ViewController 's ViewDidLoad like below:-

class General: UILibraryFunction {

override func viewDidLoad() {
super.viewDidLoad()

//-- top bar ------
setTitle(BarTitle: "Header")
rightBarButton()
leftBarButton()

}
}

Accessing UserDefaults in Swift from other viewControllers

Several things.

You should be using set(_:forKey:) and object(_:forKey) to read and write key/value pairs to defaults, not setValue(_:forKey). (Your use of defaults.string(forKey: "loginStatus") is correct, however.)

You should probably be writing a nil to the userName key:

defaults.set(nil, forKey: "username")

And your logout IBAction should almost certainly be setting loginStatus to false, not true.

Try changing those things.

Also, there is no reason to call synchronize unless you are terminating your app in Xcode rather than pressing the home button on the device/simulator in order to let it exit normally.

How to present login screen only when a userdefaults key doesn't exist?

You just need to in the Appdelegate.swift's application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) method to judge.

But the precondition is you should manual operation the window:

Delete this line in your info.plist:
Sample Image

Then in your AppDelegate.swift you can set your window manually:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.

self.window = UIWindow.init(frame: UIScreen.main.bounds)

let sb:UIStoryboard = UIStoryboard.init(name: "Main", bundle: nil)

let isLogin:Bool = UserDefaults.standard.bool(forKey: "isLogin")
if isLogin {

let vc2 = sb.instantiateViewController(withIdentifier: "ViewController2")

self.window?.rootViewController = vc2
}else {
let vc1 = sb.instantiateViewController(withIdentifier: "ViewController")
self.window?.rootViewController = vc1
}

self.window?.makeKeyAndVisible()

return true
}

And in your ViewController.swift(you can regard it as LoginVc):

override func viewDidLoad() {
super.viewDidLoad()

/* add userdefaults */

UserDefaults.standard.set(true, forKey: "isLogin")
UserDefaults.standard.synchronize()

}

Best practices for Storyboard login screen, handling clearing of data upon logout

Here is what I ended up doing to accomplish everything. The only thing you need to consider in addition to this is (a) the login process and (b) where you are storing your app data (in this case, I used a singleton).

Storyboard showing login view controller and main tab controller

As you can see, the root view controller is my Main Tab Controller. I did this because after the user has logged in, I want the app to launch directly to the first tab. (This avoids any "flicker" where the login view shows temporarily.)

AppDelegate.m

In this file, I check whether the user is already logged in. If not, I push the login view controller. I also handle the logout process, where I clear data and show the login view.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{

// Show login view if not logged in already
if(![AppData isLoggedIn]) {
[self showLoginScreen:NO];
}

return YES;
}

-(void) showLoginScreen:(BOOL)animated
{

// Get login screen from storyboard and present it
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
LoginViewController *viewController = (LoginViewController *)[storyboard instantiateViewControllerWithIdentifier:@"loginScreen"];
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:viewController
animated:animated
completion:nil];
}

-(void) logout
{
// Remove data from singleton (where all my app data is stored)
[AppData clearData];

// Reset view controller (this will quickly clear all the views)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
MainTabControllerViewController *viewController = (MainTabControllerViewController *)[storyboard instantiateViewControllerWithIdentifier:@"mainView"];
[self.window setRootViewController:viewController];

// Show login screen
[self showLoginScreen:NO];

}

LoginViewController.m

Here, if the login is successful, I simply dismiss the view and send a notification.

-(void) loginWasSuccessful
{

// Send notification
[[NSNotificationCenter defaultCenter] postNotificationName:@"loginSuccessful" object:self];

// Dismiss login screen
[self dismissViewControllerAnimated:YES completion:nil];

}


Related Topics



Leave a reply



Submit