在逃避关闭的函数中抛出错误

时间:2017-12-30 22:11:27

标签: swift escaping closures try-catch throw

我正在尝试编写一个在Firebase中注册新用户的自定义函数。我在名为DatabaseManager的类中导入了Firebase。在那里,我管理所有数据库交互。在本课程中,我希望有一个自定义函数来添加用户,这会抛出所有Firebase错误。这样我就可以在ViewController类中使用该函数,我可以捕获错误并显示警报。 但是我似乎无法使功能正常工作,我不确定我做错了什么。

这是我的功能:

enum createAccountError : Error{
        case emailInUse, weakPassword, networkError, unknownError
    }

    //Mark: create a user profile
    ///create account with email, password, username, phoneNumber, birthDate, name
    func createAccount(_ userModel: UserModel, _ password: String?, completion: @escaping (_ inner: ()throws -> Bool)->())  {
        Auth.auth().createUser(withEmail: userModel.email!, password: password!, completion: {(user, error) in
            if let error = error {
                if let errCode = AuthErrorCode(rawValue: error._code) {
                    switch errCode {
                    case .emailAlreadyInUse:
                        completion({throw createAccountError.emailInUse})
                    case .weakPassword:
                        completion({throw createAccountError.weakPassword})
                    case .networkError:
                        completion({throw createAccountError.networkError})
                    default:
                        completion({throw createAccountError.unknownError})
                    }
                }
                return
            } else {
                completion({return true})
            }
        })
    }

以下是我尝试使用它的方法:

DatabaseManager.system.createAccount(user, password) { (( inner: ()throws -> Bool)->()) in
            do{
                let result = try inner()
            } catch .emailInUse{
                //show alert
            }
            }

2 个答案:

答案 0 :(得分:1)

我建议按如下方式重构您的函数:

func createAccount(_ userModel: UserModel, _ password: String?, completion: @escaping(Error?) -> ())  {
    Auth.auth().createUser(withEmail: userModel.email!, password: password!, completion: {(user, error) in
        if let error = error {
            if let errCode = AuthErrorCode(rawValue: error._code) {
                switch errCode {
                case .emailAlreadyInUse:
                    completion(createAccountError.emailInUse)
                case .weakPassword:
                    completion(createAccountError.weakPassword)
                case .networkError:
                    completion(createAccountError.networkError)
                default:
                    completion(createAccountError.unknownError)
                }
            }

        } else {
            completion(nil)
        }
    })
}

然后当你调用该函数时,你可以检查是否有这样的错误:

DatabaseManager.system.createAccount(user, password) { (error) in
   guard error == nil else {
      //Handle error
      return
   }

   //There was no error

答案 1 :(得分:1)

我已经为演示创建了测试功能,一切正常

// error type
enum TestError: Error { case notFound, empty }
// define typealias for eiser usage of complex function type
typealias ThrowableCallback = () throws -> Bool

func createAccount(_ shouldThrow: Bool, completion: @escaping (_ inner: ThrowableCallback) -> Void) {
  // call completion callback asynchronously
  DispatchQueue.main.async {
    if shouldThrow {
      // throw error
      completion({ throw TestError.notFound })
    }
    // return value
    completion({ return true })
  }
}

用法:

createAccount(true) { (inner: ThrowableCallback) -> Void in
        do {
          let success = try inner()
          print(success)
        } catch {
          print(error)
        }
      }
UPD:我不建议使用这种技术处理异步函数中的错误。使用单独的回调表示成功和失败,或者Promises正常处理异步代码(请查看this以获取更多信息)

UPD 2:实际解决方案

typealias ThrowableCallback = () throws -> User 
func createAccount(_ userModel: UserModel,
                   _ password: String,
                   completion: @escaping (_ inner: ThrowableCallback) -> Void) {
  Auth.auth().createUser(withEmail: userModel.email!, password: password!, completion: {(user, error) in 
    if let error = error { completion({ throw error }) } 
    else { completions({ return user! }) } 
  }) 
}

// usage
createAccount(userModel, somePassword) { (inner: ThrowableCallback) -> Void in
        do {
          let createdUser = try inner()
        } catch {
          ler errCode = (error as NSError)._code
          switch errCode {
             case .emailAlreadyInUse:
               showAlert("Email is already in use")
             case .weakPassword:
               showAlert("please enter stronger password ")
             case .networkError:
               showAlert("it seams that there is no internet connection")
             default:
               showAlert("Error creating user. Please try again later")
             }
        }
      }