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:
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:
and you Storyboard should look like this:
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
:
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).
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
Alert View Is Showing White Rectangle in iOS7
What Impact Does Simulated Metrics Have
Swift Force-Unwrapping Exception Not Propagated
Is Possible to Simulate Touch Event Using an External Keyboard on iOS Jailbroken
Xcode: Failed to Get the Task for Process
Bundle.Main.Path(Forresource:Oftype:Indirectory:) Returns Nil
iOS - Ensure Execution on Main Thread
Make Part of a Uilabel Bold in Swift
Set Rootviewcontroller of Uinavigationcontroller by Method Other Than Initwithrootviewcontroller
How to Use Networkreachabilitymanager in Alamofire
Nsinternalinconsistencyexception, Reason: Could Not Load Nib in Bundle
How to Edit Uialertaction Text Font Size and Color
Mkmapview Show Incorrectly Saved Region
Presenting Uiviewcontroller from Skscene
How to Get Core Data Object from Specific Object Id
How to Call a View Controller Programmatically
Xcode 6 Storyboard Unwind Segue with Swift Not Connecting to Exit