首页 > 解决方案 > Firebase SwiftUI and Firebase Auth - not reading user ID?

问题描述

Below is the code for my signup page. I want to make it so that when someone creates an account on the sign up page, I create a document in the users collection and include uuid in the document. However, session.session?.uid ends up being nil. Does anyone know why this is?

struct SignUpView: View {
    @State var email = ""
    @State var password = ""
    @State var name = ""
    @State var error = ""
    @EnvironmentObject var session: SessionStore

    func signUp() {
        let db = Firestore.firestore()
        let user = db.collection("users").document()
        let test = db.collection("users").document(user.documentID).collection("routines").document()
        session.signUp(email: email, password: password) { (result, error) in
            if let error = error {
                self.error = error.localizedDescription
                print("This is the error \(error)")
                return
            } else {
                self.email = ""
                self.password = ""
            }
        }

        user.setData(["id": user.documentID, "email": email]) { (err) in
            if err != nil {
                print((err?.localizedDescription)!)
                return
            }
        }
        print(session.session?.uid)
        test.setData(["id:": test.documentID, "msg": "samwell Tarly", "uuid": session.session?.uid]) { (err) in
            print("ummmmm test data?")
            if err != nil {
                print((err?.localizedDescription)!)
                return
            }
        }
    }

标签: firebasefirebase-authenticationswiftui

解决方案


The Firebase APIs are asynchronous, simply because they access a remote system, across the internet, which takes a little time. The same applies for accessing the local disk, by the way. This blog post explains this in more detail.

Consequently, session.signUp is an asynchronous process. I.e. the call to print(session.session?.uid) is executed before session.signUp returns. Thus, session.session?.uid is still nil.

To work around this, you can nest your calls like this:

session.signUp(email: email, password: password) { (result, error) in
  if let error = error {
    self.error = error.localizedDescription
    print("This is the error \(error)")
    return
  } 
  else {
    self.email = ""
    self.password = ""

    user.setData(["id": user.documentID, "email": email]) { (err) in
      if err != nil {
        print((err?.localizedDescription)!)
        return
      }
    }
  }
}

Generally speaking, I would strongly recommend to not perform so much logic in your views, but instead keep your views as anaemic as possible - meaning: put all your logic into view models, and bind the view to the view models by using Combine. This will make your code much cleaner, easier to test, and maintainable.

See https://peterfriese.dev/replicating-reminder-swiftui-firebase-part2/ for how to do this.


推荐阅读