Stay logged in with Firebase Authentication Xcode

I have an app that is already connected to Firebase and has an email/password login. However, when I log in to the app and close the app, it does not stay logged in. I’ve tried a few things from other threads (one of which is inside of my current code), but none of them have been successful. Anything helps, thanks!

LoginEmailViewController:

import UIKit
import FirebaseAuth

class LoginEmailViewController: UIViewController {
    
    let userDefault = UserDefaults.standard
    let launchedBefore = UserDefaults.standard.bool(forKey: "isLoggedIn")
    
    @IBOutlet weak var loginEmailTextField: UITextField!
    @IBOutlet weak var loginPasswordTextField: UITextField!
    @IBOutlet weak var loginButton: UIButton!
    @IBOutlet weak var loginErrorLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // if user is already signed in, go to tabBarController screens
        if userDefault.bool(forKey: "usersignedin") {
            performSegue(withIdentifier: "signInSegue", sender: self)
        }
        
        setUpElements()
    }

    func setUpElements() {
        
        // hide error label
        loginErrorLabel.alpha = 0
        
        // style the textfields
        Utilities.styleTextField(loginEmailTextField)
        Utilities.styleTextField(loginPasswordTextField)
    }
 
    @IBAction func loginTapped(_ sender: Any) {
        
        // TODO: Validate Text Fields
        
        // Create cleaned versions of the text field
        let email = loginEmailTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
        let password = loginPasswordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
        
        // Signing in the user
        Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
            if error == nil {
                // user signed in successfully, perform segue to tableViewController and set userDefault to true
                print("User signed in")
                
                self.userDefault.set(true, forKey: "usersignedin")
                self.userDefault.synchronize()

                let vc = UITableViewController()
                vc.modalPresentationStyle = .fullScreen
                self.performSegue(withIdentifier: "signInSegue", sender: nil)
                self.present(vc, animated: true)
            }
            else {
                // Couldn't sign in
                self.loginErrorLabel.text = error!.localizedDescription
                self.loginErrorLabel.alpha = 1
                
            }

        }

    }
    
}

ProfileViewController:

import UIKit
import FirebaseAuth

class ProfileViewController: UIViewController {
        
    @IBOutlet var tableView: UITableView!
    
    let data = ["Sign Out"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.delegate = self
        tableView.dataSource = self
        
        view.backgroundColor = .blue
    }
}

extension ProfileViewController: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return data.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = data[indexPath.row]
        cell.textLabel?.textAlignment = .center
        cell.textLabel?.textColor = .red
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        let signOutAction = UIAlertAction(title: "Sign Out", style: .destructive) { (action) in
            do {
                try FirebaseAuth.Auth.auth().signOut()
                
                let vc = WelcomeViewController()
                vc.modalPresentationStyle = .fullScreen
                self.performSegue(withIdentifier: "logOutSegue", sender: nil)
                self.present(vc, animated: true)
                
                print("Successfully logged out")
                
            } catch let err {
                print("Failed to log out", err)
                Service.showAlert(on: self, style: .alert, title: "Sign Out Error", message: err.localizedDescription)
            }
        }
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
        Service.showAlert(on: self, style: .actionSheet, title: nil, message: nil, actions: [signOutAction, cancelAction], completion: nil)
    }

}

AppDelegate:

import UIKit
import Firebase
import GoogleSignIn

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    let userDefault = UserDefaults.standard
    let launchedBefore = UserDefaults.standard.bool(forKey: "isLoggedIn")
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        FirebaseApp.configure()

        return true
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }


}

The “sign out” button is inside of the ProfileViewController and the “sign in” button is inside of the LoginEmailViewController.

The Photo App in the iOS Database course is a really good example of how to store the user as being logged in even if the App is shut down. As soon as you launch the App again it interrogates user Defaults to retrieve the user currently logged in (if user did not previously log out) and if there is a user record then transitions to the appropriate ViewController.

See the courses listed at this link: https://codewithchris.com/courses/

1 Like