问题
Once the user signs in with Google, I want to take them to the home screen; however, the code does not fully execute this.
This is the code:
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in before or they have since signed out.")
} else {
print("\(error.localizedDescription)")
}
return
}
let firstName = user.profile.givenName
let lastName = user.profile.familyName
let email = user.profile.email
//Firebase sign in
guard let authentication = user.authentication else {return}
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken, accessToken: authentication.accessToken)
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print("Firebase sign In error")
print(error)
return
} else {
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["firstName": firstName!, "lastName": lastName!, "email": email!, "uid": authResult!.user.uid]) { (error) in
if error != nil {
print("Error: User data not saved")
}
}
print("User is signed in with Firebase")
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeVC") as! HomeViewController
self.window?.rootViewController = homeViewController
self.window?.makeKeyAndVisible()
}
}
}
More specifically:
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print("Firebase sign In error")
print(error)
return
} else {
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["firstName": firstName!, "lastName": lastName!, "email": email!, "uid": authResult!.user.uid]) { (error) in
if error != nil {
print("Error: User data not saved")
}
}
print("User is signed in with Firebase")
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeVC") as! HomeViewController
self.window?.rootViewController = homeViewController
self.window?.makeKeyAndVisible()
}
}
the print("User is signed in with Firebase")
does take place but it fails to switch the HomeViewController and I'm not sure what it is that I am doing wrong here.
回答1:
The problem in the code is that Firebase is asynchronous. So this section
} else {
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["firstName": firstName!, "lastName": lastName!, "email": email!, "uid": authResult!.user.uid]) { (error) in
if error != nil {
print("Error: User data not saved")
}
}
print("User is signed in with Firebase")
This print statement
print("User is signed in with Firebase")
will execute before the code within the closure. The reason is the code is faster than the internet - you have to 'wait' for data to be returned from Firebase before moving forward in your code. To fix, move the statements inside the closure so they execute when Firebase returns
} else {
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["firstName": firstName!, "lastName": lastName!, "email": email!, "uid": authResult!.user.uid]) { (error) in
if error != nil {
print("Error: User data not saved")
return
}
print("User is signed in with Firebase")
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeVC") as! HomeViewController
self.window?.rootViewController = homeViewController
self.window?.makeKeyAndVisible()
}
Note that with this code flow, every time an existing user signs it, it will create a new document in the users collection. That's probably not the intention.
回答2:
My guess is that window is nil and that's why your code isn't executing properly. Try the code below if you are targeting iOS 13. Ideally, you would want to move the Sign-in code inside SceneDelegate and duplicate it in AppDelegate if your app also supports iOS 12, 11 etc.
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print("Firebase sign In error")
print(error)
return
} else {
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["firstName": firstName!, "lastName": lastName!, "email": email!, "uid": authResult!.user.uid]) { (error) in
if error != nil {
print("Error: User data not saved")
}
}
print("User is signed in with Firebase")
DispatchQueue.main.async {
let scene = UIApplication.shared.connectedScenes.first
if let sceneDelegate = scene?.delegate as? SceneDelegate {
let window = sceneDelegate?.window
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homeViewController = mainStoryboard.instantiateViewController(withIdentifier: "HomeVC") as! HomeViewController
window?.rootViewController = homeViewController
window?.makeKeyAndVisible()
}
}
}
}
来源:https://stackoverflow.com/questions/62354073/how-do-i-switch-to-a-different-view-controller-from-the-app-delegate