Reputation: 13803
I am trying to make a login system using google account to firebase authentication.
if the user login using google account for the first time, then they have to pick their city domicile first before go to HomeVC otherwise they can go straight to homeVC.
To tackle this issue, first I try to get the data from firebase database. if the user has been login before, then they will have user database in my firebase. so, the result from snapshot.value
from observe
it will be stored to userBasicInformation
.
if the user login for the first time then userBasicInformation
should be nil. but I don't know why the line of code that retrieve the data from my firebase database below seems never be executed in the first time
Database.database().reference().child("users/\(userKM.uid)").reference().observe
here is the simplified code of this login system. I give print number to track the code. the print result is below
import UIKit
import Firebase
import GoogleSignIn
// variable that store user basic data (uid, fullname, email, domicile)
var userBasicInformation : [String:Any]?
// sign in using google account to Firebase Authenctication
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error {
print("failed to create firebase user using google account")
print("\(error.localizedDescription)")
return
}
print("user successfully logged into firebase")
print("1")
guard let userKM = user else { return }
print("2")
// retrieve User Basic data from firebase database
Database.database().reference().child("users/\(userKM.uid)").reference().observe(.value, with: { (snapshot) in
print("3")
if let valueDictionary = snapshot.value as? [String:Any] {
let userValue = User(dictionary: valueDictionary)
let userInformation : [String:Any] = [
"uid" : userValue.uid,
"fullname" : userValue.fullname,
"email" : userValue.email,
"domicile" : userValue.domicile
]
userBasicInformation = userInformation
} else {
print("4")
// if there is no snapshott.value (no database for certain uid) then set to nil. it means user logged in using gmail forthe first time
userBasicInformation = nil
}
})
// if user has signed up before then send to mainTabBar (it means he/she has picked a city), otherwise pickCity first
// if the user sign Up for the first time, then userBasicInformation will be nil because there is no user default available
if userBasicInformation == nil {
print("5")
// save user data to Firebase Database
let userX = User(uid: userKM.uid, fullname: userKM.displayName!, email: userKM.email!)
userX.save(completion: { (error) in
if error != nil {
print(error!)
}
})
// assign Value to superGlobal Variable
userBasicInformation = [
"uid" : userX.uid as Any,
"fullname" : userX.fullname as Any,
"email" : userX.email as Any,
"domicile" : userX.domicile as Any
]
self.pickCity()
} else {
print("6")
self.goToMainTabBar()
}
}
}
here is the result from my debugging area
- user successfully signin into google
- user successfully logged into firebase
- 1
- 2
- 5
- 3
i don't understand why '3' which is 'retrieving data from firebase database' using observe seems never be executed first
i expect 1 -> 2 -> 3 -> 5 , but i got 1 -> 2 -> 5 -> 3
thats why userBasicInformation
always be nil if i restart the simulator
why my observe value doesn't work for the first time?
Upvotes: 0
Views: 237
Reputation: 16426
It is obvious.
Your execution of Database.database().reference().child("users/\(userKM.uid)").reference().observe(.value, with: { (snapshot) in
is async operation and it will executed after response form your request
while you are
checking if userBasicInformation == nil {
condition next to the that async block child("users/\(userKM.uid)")
, so it will executed first. (It will not wait for your firebase request child("users/\(userKM.uid)")
to finish)
To Fix this Put all the if userBasicInformation == nil {
and else
block in the your firebase request block.
Hope it is helpful to you
EDIT\UPDATE
I don't understand why you are checking if userBasicInformation == nil {
after putting this stuff inside users/\(userKM.uid)"
you don't need to check it is nil or not
if you wan't to user to login automatically if he did before then
in viewDidLoad
put
GIDSignIn.sharedInstance().signInSilently()
Auth.auth().addStateDidChangeListener { (auth, user) in
if user != nil {
// HERE YOU CAN PERFORM ANYTHING LIKE SAVING TO USERDEFAULT OR ANYTHING AFTER USER LOGGED IN
UserDefaults.standard.setValue(user?.uid, forKeyPath: "uid")
self.performSegue(withIdentifier: "CurrentlyLoggedIn", sender: nil)
}
}
Upvotes: 1