David Henry
David Henry

Reputation: 3046

Current Firebase User Returning Nil

I have an app using FirebaseAuth to authenticate users. I do this in an AuthService class;

import Foundation
import FirebaseAuth
class AuthService: NSObject {
    
    private override init() {}
    
    static let shared = AuthService()
    
    let currentUser = Auth.auth().currentUser
    var uid = Auth.auth().currentUser?.uid

    func checkAuthState(completion: @escaping(FirebaseAuth.User?) -> Void) {
//        let listener = Auth.auth().addStateDidChangeListener { (auth, user) in
        Auth.auth().addStateDidChangeListener { (auth, user) in
            switch user {
            case .none:
                print("USER NOT FOUND IN CHECK AUTH STATE")
                completion(nil)
            case .some(let user):
                print("USER FOUND WITH ID: \(user.uid)")
                completion(user)
            }
        }
//        Auth.auth().removeStateDidChangeListener(listener)
    }
}

I then sign in a user anonymously using checkAuthState function above. Once this operation completes with some user I perform an action to switch the rootViewController.

func checkAuthState() {
        authService.checkAuthState { (user) in
            switch user {
            case .none:
                SceneDelegate.shared.rootController.showWelcomeController()
            case .some(_):
                SceneDelegate.shared.rootController.showTabBarController()
            }
        }
    }
}

Here is my code within my RootViewController;

func showWelcomeController() {
        let welcomeController = WelcomeController(authService: AuthService.shared)
        let navigationController = UINavigationController(rootViewController: welcomeController)
        addChild(navigationController)
        navigationController.view.frame = view.frame
        view.addSubview(navigationController.view)
        navigationController.didMove(toParent: self)
        currentController.willMove(toParent: nil)
        currentController.view.removeFromSuperview()
        currentController.removeFromParent()
        currentController = navigationController
    }
    
    func showTabBarController() {
        let tabBarController = TabBarController()
        addChild(tabBarController)
        tabBarController.view.frame = view.frame
        view.addSubview(tabBarController.view)
        tabBarController.didMove(toParent: self)
        currentController.willMove(toParent: nil)
        currentController.view.removeFromSuperview()
        currentController.removeFromParent()
        currentController = tabBarController
    }

The above operates all as expected and shows my TabBarController, however, I then run a function in one of my ViewControllers in my TabBarController which is;

var uid = Auth.auth().currentUser?.uid

func readComments(query: Query, lastDocument: DocumentSnapshot?, completion: @escaping(Result<[CommentModel], NetworkError>) -> ()) {
        guard let uid = auth.uid else { return completion(.failure(.userNotFound)) }
// Other code

}

However, I get the .userNotFound error? as it returns nil? I'm confused as checkAuthState is returning a user?

Upvotes: 0

Views: 455

Answers (1)

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

This typically means that the currentUser is not yet initialized by the time that code runs. Since restoring the user's sign-in state requires a call to the server, it is an asynchronous operation.

Any code that depends on the current user state being restored should be inside (or be called from) an addStateDidChangeListener as in your first snippet. So you may need a snippet like that in your other view controller(s) too.

Upvotes: 1

Related Questions