【问题标题】:How do I switch to a different view controller from the App Delegate?如何从 App Delegate 切换到不同的视图控制器?
【发布时间】:2020-10-02 20:23:00
【问题描述】:

用户使用 Google 登录后,我想将他们带到主屏幕;但是,代码并没有完全执行。

这是代码:

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()

        }
    }
}

更具体地说:

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()

        }
    }

print("User is signed in with Firebase") 确实发生了,但它无法切换 HomeViewController,我不确定我在这里做错了什么。

【问题讨论】:

  • 查看我的回答,但作为后续问题,`.signIn' 功能是登录现有用户。使用此代码流,每次现有用户登录时,都会在 users 集合中创建一个新文档 - 这是您想要的吗?
  • 不,不是。正在努力。

标签: ios swift firebase firebase-authentication google-signin


【解决方案1】:

我的猜测是 window 为 nil,这就是您的代码无法正常执行的原因。如果您的目标是 iOS 13,请尝试以下代码。理想情况下,如果您的应用还支持 iOS 12、11 等,您可能希望将登录代码移动到 SceneDelegate 中并在 AppDelegate 中复制它。

   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()

                }
            }
        }
    }

【讨论】:

  • 那我怎样才能让它只在用户完成登录的情况下运行呢?
  • @KoolKid 如果这个答案是指 Firebase 闭包,那么 Firebase 闭包中的 UI 调用都是 called on the main thread,因此不需要 DispatchQueues。
  • @KoolKid 如果你的目标是 iOS13,试试我刚刚发布的代码。理想情况下,如果您的应用还支持 iOS 12、11 等,您可能希望将登录代码移动到 SceneDelegate 中并在 AppDelegate 中复制它。
  • 你能解释一下AppDelegate和SceneDelegate的区别吗?我对 Swift 很熟悉,但对应用程序开发不太熟悉,所以我不确定这会发生什么变化。
  • 这里有一个很好的解释:stackoverflow.com/questions/56498099/…你有机会尝试代码吗?
【解决方案2】:

代码中的问题是 Firebase 是异步的。所以本节

} 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")

这个打印语句

print("User is signed in with Firebase")

将在闭包内的代码之前执行。原因是代码比互联网快 - 您必须“等待”数据从 Firebase 返回,然后才能继续执行代码。要解决此问题,请移动闭包内的语句,以便它们在 Firebase 返回时执行

} 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()
    }

请注意,使用此代码流,每次现有用户签名时,都会在 users 集合中创建一个新文档。这可能不是本意。

【讨论】:

  • 是的,我仍在努力解决每次登录时都会创建新文档的问题。所以我尝试了return语句,但它仍然不会将视图控制器更改为homeViewController。我的问题不是登录有问题,而是一旦他们登录,打印后的一切都没有按预期进行。我觉得我的“措辞”有问题。
  • @KoolKid 您什么时候想要在 Firestore 中创建这些数据?我认为是当用户第一次用.createUser.创建之后,就不需要在.signIn函数中重新创建文档
  • 是的,我只想创建一次数据。 .createUser 发生在用户使用电子邮件创建帐户时。在这种情况下,用户正在使用他们的 Google 帐户进行签名。我想使用 Auth.auth().createUser() 但我不确定创建用户的参数会包含什么。通常 Auth.auth().createUser(withEmail: email, password: password) 会起作用,但我不确定 Google 帐户。
  • 这里有两点说明:(1)看看FirebaseUI,这将使创建注册/登录体验更加容易。 (2) 如果您想为新创建的用户运行代码一次,请编写一个在创建新用户时触发的 Firebase Cloud Function。详情请见Extend Firebase Authentication with Cloud Functions
猜你喜欢
  • 2012-06-21
  • 1970-01-01
  • 2023-03-17
  • 1970-01-01
  • 2012-03-30
  • 2011-06-05
  • 1970-01-01
  • 2018-04-22
  • 2012-10-28
相关资源
最近更新 更多