如何在创建帐户之前检查电子邮件是否已经存在(Swift)

时间:2019-07-31 01:01:25

标签: swift firebase firebase-realtime-database firebase-authentication

我知道有人问过这个问题的不同变化。但是我似乎每次都遇到相同的问题。

我想在用户推送到下一个视图之前检查电子邮件是否已经存在。我将输入数据库中存在的电子邮件,并且始终调用performSegue函数,并将用户推入,就像该电子邮件不存在一样。

我可以正式检查的唯一方法是,当用户到达最终注册VC时,Auth.auth().createUser(withEmail: email as! String, password: password as! String ) { (user, error) in代码将检查所有错误。

但是,为了获得良好的用户体验,我不希望用户必须单击三下以更改电子邮件地址。这是我用于输入电子邮件视图控制器的代码。

   // Check if email is already taken
        Auth.auth().fetchSignInMethods(forEmail: emailTextField.text!, completion: { (forEmail, error) in
                // stop activity indicator
                self.nextButton.setTitle("Continue", for: .normal)
                self.activityIndicator.stopAnimating()


                if let error = error {
                    print("Email Error: \(error.localizedDescription)")
                    print(error._code)
                    self.handleError(error)
                    return

                } else {
                    print("Email is good")
                    self.performSegue(withIdentifier: "goToCreateUsernameVC", sender: self)

                }

        })

首先,我是否还要在forEmail部分中输入create属性?我添加了emailTextField.text,因为这是我甚至知道如何获得用户键入的电子邮件的唯一方法。有谁知道我可以做的更好的方法?

1 个答案:

答案 0 :(得分:1)

我如何创建用户帐户

这是我使用的示例。当用户提供凭据时,FirebaseAuth将检查这些凭据是否可用于创建用户帐户。该函数返回两个值,一个布尔值(指示创建是否成功)和一个可选错误(当创建失败时返回)。如果布尔值返回true,我们只需推送到下一个视图控制器即可。否则,我们会显示错误。

func createUserAcct(completion: @escaping (Bool, Error?) -> Void) {

    //Try to create an account with the given credentials
    Auth.auth().createUser(withEmail: emailTextField.text!, password: passwordConfirmTextField.text!) { (user, error) in
        if error == nil {

            //If the account is created without an error, then we will make a ProfileChangeRequest, i.e. update the user's photo and display name.
            if let firebaseUser = Auth.auth().currentUser {

                let changeRequest = firebaseUser.createProfileChangeRequest()
                //If you have a URL for FirebaseStorage where the user has uploaded a profile picture, you'll pass the url here
                changeRequest.photoURL = URL(string: "nil")
                changeRequest.displayName = self.nameTextField.text!
                changeRequest.commitChanges { error in
                    if let error = error {
                        // An error happened.
                        completion(false, error)
                    } else {
                        //If the change is committed successfully, then I create an object from the credentials. I store this object both on the FirebaseDatabase (so it is accessible by other users) and in my user defaults (so that the user doesn't have to remotely grab their own info

                        //Create the object
                        let userData = ["email" : self.emailTextField.text!,"name": self.nameTextField.text!] as [String : Any]

                        //Store the object in FirebaseDatabase
                        Database.database().reference().child("Users").child(firebaseUser.uid).updateChildvalues(userData)
                        //Store the object as data in my user defaults
                        let data = NSKeyedArchiver.archivedData(withRootObject: userData)
                        UserDefaults.standard.set(data, forKey: "UserData")
                        UserDefaults.standard.set([Data](), forKey: "UserPhotos")
                        completion(true, nil)
                    }
                }
            }
        } else {
            // An error happened.
            completion(false, error)
        }
    }
}

这是我将如何使用它的一个示例。我们可以使用返回的成功布尔值来确定是应该推送到下一个视图控制器,还是向用户显示错误警报。

createUserAcct { success, error in
    //Handle the success
    if success {
        //Instantiate nextViewController
        let storyboard = UIStoryboard(name: "Main", bundle: .main)
        let nextVC = storyboard.instantiateViewController(withIdentifier: "NextVC") as! NextViewController

        //Push typeSelectVC
        self.navigationController!.pushViewController(viewController: nextVC, animated: true, completion: {
            //We are no longer doing asynchronous work, so we hide our activity indicator
            self.activityIndicator.isHidden = true
            self.activityIndicator.stopAnimating()
        })
    } else {
        //We now handle the error
        //We are no longer doing asynchronous work, so we hide our activity indicator
        self.activityIndicator.isHidden = true
        self.activityIndicator.stopAnimating()

        //Create a UIAlertController with the error received as the message (ex. "A user with this email already exists.")
        let alertController = UIAlertController(title: "Error", message: error!.localizedDescription, style: .alert)
        let ok = UIAlertAction(title: "OK", style: .cancel, action: nil)

        //Present the UIAlertController
        alertController.addAction(ok)
        self.present(alertController, animated: true, completion: nil)
    }

}

让我知道这一切是否有意义,我知道还有很多。我只是在考虑可能会发现您需要做的事情,这些事情可能是您可能不知道的(例如发出更改请求或将数据对象存储在FirebaseDatabase上)。

现在可以检查电子邮件是否已被接收:

还记得我说过在创建帐户时将用户对象发布到FirebaseDatabase吗?好吧,我们可以查询给定的电子邮件以查看它是否已经存在。如果没有,我们将继续按正常流程进行操作,而无需实际创建帐户。否则,我们只是告诉用户选择另一个电子邮件地址。

将用户对象推入数据库(取自上面的代码):

if let firebaseUser = Auth.auth().currentUser {
    //Create the object
    let userData = ["email" : self.emailTextField.text!,"name": self.nameTextField.text!] as [String : Any]

    //Store the object in FirebaseDatabase
    Database.database().reference().child("Users").child(firebaseUser.uid).updateChildvalues(userData)
}

现在查询是否有人已收到该电子邮件:

func checkIfEmailExists(email: String, completion: @escaping (Bool) -> Void ) {

    Database.database().reference().child("Users").queryOrdered(byChild: "email").queryEqual(toValue: email).observeSingleEvent(of: .value, with: {(snapshot: DataSnapshot) in

        if let result = snapshot.value as? [String:[String:Any]] {
            completion(true)
        } else {
            completion(false)
        }
    }
}

然后我们可以这样称呼它:

checkIfEmailExists(email: emailTextField.text!, completion: {(exists) in 
    if exists {
        //Present error that the email is already used
    } else {
        //Segue to next view controller
    }
})