Handling Errors in New Firebase and Swift

15,683

Solution 1

I've actually just struggled with this for quite a bit of time and found what the issue was. I've tried the code posted in an answer above and the error.code line gave me an error. It did work with error._code though. In other words, credit for the original answer to Paul with a slight modificaiton. Here's my final code (I will edit it for all errors though):

if let errCode = AuthErrorCode(rawValue: error!._code) {

    switch errCode {
        case .errorCodeInvalidEmail:
            print("invalid email")
        case .errorCodeEmailAlreadyInUse:
            print("in use")
        default:
            print("Create User Error: \(error)")
    }    
}

Solution 2

Updated for Swift 4 + Firebase 4 + UIAlertController

extension AuthErrorCode {
    var errorMessage: String {
        switch self {
        case .emailAlreadyInUse:
            return "The email is already in use with another account"
        case .userNotFound:
            return "Account not found for the specified user. Please check and try again"
        case .userDisabled:
            return "Your account has been disabled. Please contact support."
        case .invalidEmail, .invalidSender, .invalidRecipientEmail:
            return "Please enter a valid email"
        case .networkError:
            return "Network error. Please try again."
        case .weakPassword:
            return "Your password is too weak. The password must be 6 characters long or more."
        case .wrongPassword:
            return "Your password is incorrect. Please try again or use 'Forgot password' to reset your password"
        default:
            return "Unknown error occurred"
        }
    }
}


extension UIViewController{
    func handleError(_ error: Error) {
        if let errorCode = AuthErrorCode(rawValue: error._code) {
            print(errorCode.errorMessage)
            let alert = UIAlertController(title: "Error", message: errorCode.errorMessage, preferredStyle: .alert)

            let okAction = UIAlertAction(title: "Ok", style: .default, handler: nil)

            alert.addAction(okAction)

            self.present(alert, animated: true, completion: nil)

        }
    }

}

Usage example:

    Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in

        if error != nil {
            print(error!._code)
            self.handleError(error!)      // use the handleError method
            return
        }
        //successfully logged in the user

    })

Solution 3

Even though this has been answered correctly, wanted to share a nice implementation for this we added to our project.

This can be done for other error types as well, but we just needed it for the FIRAuthErrorCodes.

If you extend FIRAuthErrorCode to have a variable errorMessage of type string, you can have your own error messages for the users:

extension FIRAuthErrorCode {
    var errorMessage: String {
        switch self {
        case .errorCodeEmailAlreadyInUse:
            return "The email is already in use with another account"
        case .errorCodeUserDisabled:
            return "Your account has been disabled. Please contact support."
        case .errorCodeInvalidEmail, .errorCodeInvalidSender, .errorCodeInvalidRecipientEmail:
            return "Please enter a valid email"
        case .errorCodeNetworkError:
            return "Network error. Please try again."
        case .errorCodeWeakPassword:
            return "Your password is too weak"
        default:
            return "Unknown error occurred"
        }
    }
}

You could customize only some as we have above and group the rest under "Unknown error".

With this extension you can handle an error as shown in Vladimir Romanov's answer:

func handleError(_ error: Error) {
    if let errorCode = FIRAuthErrorCode(rawValue: error._code) {
        // now you can use the .errorMessage var to get your custom error message
        print(errorCode.errorMessage)
    }
}

Solution 4

FIRAuthErrorCode is an int enum not a string enum. Do the following:

if let error = error {
        switch FIRAuthErrorCode(rawValue: error.code) !{
                case .ErrorCodeInvalidEmail:

More info in this answer.

Share:
15,683

Related videos on Youtube

Mariah
Author by

Mariah

Updated on June 06, 2022

Comments

  • Mariah
    Mariah about 2 years

    I'm trying to add error handling in creating user button in iOS project using swift and firebase:

    Here's the code for the button:

         @IBAction func Register(sender: AnyObject) {
    
        if NameTF.text == "" || EmailTF.text == "" || PasswordTF.text == "" || RePasswordTF == "" || PhoneTF.text == "" || CityTF.text == ""
        {
            let alert = UIAlertController(title: "عذرًا", message:"يجب عليك ملىء كل الحقول المطلوبة", preferredStyle: .Alert)
            alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
            self.presentViewController(alert, animated: true){}
    
        } else {
    
            if PasswordTF.text != RePasswordTF.text {
                let alert = UIAlertController(title: "عذرًا", message:"كلمتي المرور غير متطابقتين", preferredStyle: .Alert)
                alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
                self.presentViewController(alert, animated: true){}
    
            } else {
    
    
                FIRAuth.auth()?.createUserWithEmail(EmailTF.text!, password: PasswordTF.text!, completion: { user, error in
                    print(error)
    
                    if error != nil {
    
                        let errorCode = FIRAuthErrorNameKey
    
                        switch errorCode {
                        case "FIRAuthErrorCodeEmailAlreadyInUse":
                            let alert = UIAlertController(title: "عذرًا", message:"الإيميل مستخدم", preferredStyle: .Alert)
                            alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
                            self.presentViewController(alert, animated: true){}
    
                        case "FIRAuthErrorCodeUserNotFound":
                            let alert = UIAlertController(title: "عذرًا", message:"المستخدم غير موجود", preferredStyle: .Alert)
                            alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
                            self.presentViewController(alert, animated: true){}
    
                        case "FIRAuthErrorCodeInvalidEmail":
                            let alert = UIAlertController(title: "عذرًا", message:"الإيميل غير صحيح", preferredStyle: .Alert)
                            alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
                            self.presentViewController(alert, animated: true){}
    
                        case "FIRAuthErrorCodeNetworkError":
                            let alert = UIAlertController(title: "عذرًا", message:"خطأ في الاتصال بالانترنت", preferredStyle: .Alert)
                            alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
                            self.presentViewController(alert, animated: true){}
    
                        default:
                            let alert = UIAlertController(title: "عذرًا", message:"خطأ غير معروف", preferredStyle: .Alert)
                            alert.addAction(UIAlertAction(title: "نعم", style: .Default) { _ in })
                            self.presentViewController(alert, animated: true){}
    
    
    
                        }
    
    
                    } else {
    
                        FIRAuth.auth()?.signInWithEmail(self.EmailTF.text!, password: self.PasswordTF.text!, completion: { (user: FIRUser?, error: NSError?) in
                            if let error = error {
                                print(error.localizedDescription)
                            } else {
    
                               self.ref.child("UserProfile").child(user!.uid).setValue([
                                    "email": self.EmailTF.text!,
                                    "name" : self.NameTF.text!,
                                    "phone": self.PhoneTF.text!,
                                    "city" : self.CityTF.text!,
                                    ])
                                print("Sucess")
                              //  self.performSegueWithIdentifier("SignUp", sender: nil)
    
                            }
                        })
    
                    } //else
                })
    
            } //Big else
    
    
        } //Big Big else
    }
    
    
    }//end of
    

    I'm not sure if the syntax of the errors in switch statement is correct or not!

    Because when I tested it in the simulator it always gives me the defualt case which is unknown error! + I could not find the syntax in the documentation: https://firebase.google.com/docs/auth/ios/errors

    So, What's the correct syntax to add error handling using new firebase and swift!

  • Mariah
    Mariah over 7 years
    Before you even post the answer! I have updated my code as you posted and it worked perfectly! Thank you anyway!
  • Vladimir Romanov
    Vladimir Romanov over 7 years
    Awesome! I looked at so many resources which only mention that you can handle these faults, but not explain how, I thought I post my code after I finally got it.
  • xaphod
    xaphod about 7 years
    Note in Swift 3 i'm needing to do a bridging cast of Error to NSError, so that .code is exposed, ie. if let error = error as NSError? ...
  • Andreas
    Andreas about 7 years
    @Cesare working on my side. Mind sharing more of your code?
  • christostsang
    christostsang about 6 years
    Great answer! Works just fine with Swift 4.2 and Firebase 5.2.0. The only improvement I would do in the code is to safely unwrap the optional with " if let error = error { // user error in here without the force unwrap (!) } ". The result is the same but man, that bang operator! :)