1

I'm using Firebase in my Swift / iOS project, and am trying to implement a check to determine whether or not a user exists already in the database when they're in the sign - in / login user flow.

This is what I'm currently using as a check of whether the user exists...no matter what, even if I can visually verify that the user is in my database, I always get a result of the user not existing.

if let user = Auth.auth().currentUser {
    let ref = self.ref.child("users").child(user.uid)
    ref.observeSingleEvent(of: .value, with: { snapshot in
        self.performSegue(withIdentifier: "GoToMainViewController", sender: nil)
     })

} else {
    self.performSegue(withIdentifier: "GoToProfileCreationViewController", sender: nil)
}

I've tried the accepted in these two SO threads here and here, but am consistently getting the same result.

EDIT: This is my database structure

enter image description here

EDIT2: This is the full flow, including the code where I've authenticated the signed in user (via phone number). At both places where I'm logging the the user ID, I get that of the logged-in ID.

Auth.auth().signIn(with: credential) { (authResult, error) in
    if let error = error {
        let alert = UIAlertController(title: nil, message: error.localizedDescription, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel) { actions in
        })
        self.present(alert, animated: true)
        return
    }

    let userID = Auth.auth().currentUser?.uid

    print(userID)

    Auth.auth().addStateDidChangeListener { auth, user in
        if user != nil{
            print("user is not nil")
            //self.performSegue(withIdentifier: "GoToJoinChannelsViewController", sender: self)
        }
        else{
            print("user is nil")
            //self.performSegue(withIdentifier: "GoToProfileCreationViewController", sender: nil)
        }
    }

    print(userID)

    //Check if user exists
    if let user = Auth.auth().currentUser {
        let ref = self.ref.child("users").child(user.uid)
        ref.observeSingleEvent(of: .value, with: { snapshot in
            print(snapshot)
            //self.performSegue(withIdentifier: "GoToJoinChannelsViewController", sender: nil)
        })

    } else {
        //self.performSegue(withIdentifier: "GoToProfileCreationViewController", sender: nil)
    }

This is what the resultant snapshot looks like:

Snap (sxQLr6p9meZyQi8p8RPrjVxcUi33) {
    bio = h;
    birthday = "11-Feb-1989";
    firstname = n;
    lastname = n;
}
narner
  • 2,908
  • 3
  • 26
  • 63
  • 2
    Can you please show us your database structure? – Dan Abnormal Feb 11 '20 at 08:31
  • 1
    You tagged your question with `google-cloud-firestore`, but the code in your question accesses the Realtime Database. While both databases are part of Firebase, they have completely separate APIs, and calls to one API won't see the data in the other database. So if your data is indeed stored in Firestore, you'll need to use the Firestore API to access it. – Frank van Puffelen Feb 11 '20 at 14:42
  • @FrankvanPuffelen thank you; just updated the tags – narner Feb 11 '20 at 17:02
  • @DanAbnormal just added my database structure – narner Feb 11 '20 at 17:06
  • 1
    If you `print(user.uid)` right before attaching the listener, what does it show? Then if you `print(snapshot.value)` inside the closure, what does it show? Please add both the code and the output to your question, so that we can see exactly what is happening. – Frank van Puffelen Feb 11 '20 at 17:43
  • 1
    Hm, can’t see any obvious problem with your structure or the way you’re calling your database. Sorry if I don’t understand this, but you are certain that when making the database call currentUser isn’t nil? EDIT: just saw that @FrankvanPuffelen was pointing you in the same direction. – Dan Abnormal Feb 11 '20 at 17:58
  • Just updated with more context @FrankvanPuffelen – narner Feb 11 '20 at 19:05
  • Just updated with more context @DanAbnormal – narner Feb 11 '20 at 19:07

1 Answers1

1

You'll want to attach the database listener inside the auth state changed listener, so that it only runs once the user is authenticated:

Auth.auth().addStateDidChangeListener { auth, user in
  if user != nil {
    let ref = self.ref.child("users").child(user.uid)
    ref.observeSingleEvent(of: .value, with: { snapshot in
      if snapshot.exists() {
        // TODO: a user is signed in and registered, navigate to the next screen for them
        self.performSegue(withIdentifier: "GoToJoinChannelsViewController", sender: nil)
      }
      else {           
        // TODO: a user is signed in and not registered, navigate to the next screen for them
      }
    })
  }
  else{
    self.performSegue(withIdentifier: "GoToProfileCreationViewController", sender: nil)
  }
}
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807