我正在尝试编写一个在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
}
}
我已经为演示创建了测试功能,一切正常
// 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")
}
}
}
我建议重构你的函数如下:
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