我正在练习Swift并且有一个场景(和方法),其结果可能是成功的,也可能是失败的。
这是一个安全服务类。我有一种方法可以使用电子邮件地址和密码进行身份验证,并且如果凭据正确则返回User
实例,或者抛出某种形式的false
值。
我有点困惑,因为我对Swift方法的理解是你需要指定一个返回类型,所以我有:
class SecurityService {
static func loginWith(email: String, password: String) -> User {
// Body
}
}
我在Go和Node.js方法中看到了返回“double”值的方法,其中第一个表示任何错误,第二个是“成功”响应。我也知道Swift没有错误或异常之类的东西(但是在我学习Swift的早期版本时可能已经改变了。)
在这种情况下,适当的做法是什么?
答案 0 :(得分:10)
如果您想处理在登录过程中可能发生的错误,而不是使用Swift错误处理的强大功能:
struct User {
}
enum SecurityError: Error {
case emptyEmail
case emptyPassword
}
class SecurityService {
static func loginWith(email: String, password: String) throws -> User {
if email.isEmpty {
throw SecurityError.emptyEmail
}
if password.isEmpty {
throw SecurityError.emptyPassword
}
return User()
}
}
do {
let user = try SecurityService.loginWith1(email: "", password: "")
} catch SecurityError.emptyEmail {
// email is empty
} catch SecurityError.emptyPassword {
// password is empty
} catch {
print("\(error)")
}
或转换为可选:
guard let user = try? SecurityService.loginWith(email: "", password: "") else {
// error during login, handle and return
return
}
// successful login, do something with `user`
如果您只想获得User
或nil
:
class SecurityService {
static func loginWith(email: String, password: String) -> User? {
if !email.isEmpty && !password.isEmpty {
return User()
} else {
return nil
}
}
}
if let user = SecurityService.loginWith(email: "", password: "") {
// do something with user
} else {
// error
}
// or
guard let user = SecurityService.loginWith(email: "", password: "") else {
// error
return
}
// do something with user
答案 1 :(得分:2)
除了throw
错误的标准方法之外,您还可以使用enum
作为返回类型的关联类型
struct User {}
enum LoginResult {
case Success(User)
case Failure(String)
}
class SecurityService {
static func loginWith(email: String, password: String) -> LoginResult {
if email.isEmpty { return .Failure("Email is empty") }
if password.isEmpty { return .Failure("Password is empty") }
return .Success(User())
}
}
并称之为:
let result = SecurityService.loginWith("Foo", password: "Bar")
switch result {
case .Success(let user) :
print(user)
// do something with the user
case .Failure(let errormessage) :
print(errormessage)
// handle the error
}
答案 2 :(得分:1)
我认为调用 loginWith 的结果可以从网络请求中获得,这是我在您提供的场景中可以执行的代码:
助手班:
struct User {
var name: String
var email: String
}
class HTTP {
static func request(URL: String, method: String, params: [String: AnyObject], callback: (error: NSError?, result: [String:AnyObject]?) -> Void) -> Void {
// network request
}
}
class SecurityService {
static func loginWith(email: String, password: String, callback: (error: NSError?, user: User?) -> Void) -> Void {
let URL = ".."
let params = [
"email": email,
"password": password
]
HTTP.request(URL, method: "POST", params: params) { (error, result) in
if let error = error {
callback(error: error, user: nil)
} else {
guard let JSON = result else {
let someDomain = "some_domain"
let someCode = 100
let someInfo = [NSLocalizedDescriptionKey: "No results were sent by the server."]
let error = NSError(domain: someDomain, code: someCode, userInfo: someInfo)
callback(error: error, user: nil)
return
}
guard let name = JSON["name"] as? String, email = JSON["email"] as? String else {
let someDomain = "some_domain"
let someCode = 100
let someInfo = [NSLocalizedDescriptionKey: "No user properties were sent by the server."]
let error = NSError(domain: someDomain, code: someCode, userInfo: someInfo)
callback(error: error, user: nil)
return
}
let user = User(name: name, email: email)
callback(error: nil, user: user)
}
}
}
}
使用 SecurityService 类:
SecurityService.loginWith("someone@email.com", password: "123456") { (error, user) in
if let error = error {
print(error)
} else {
guard let user = user else {
print("no user found.")
return
}
print(user)
}
}
答案 3 :(得分:0)
返回带有关联值的结果枚举,抛出异常,并使用带有可选错误和可选用户的回调,尽管有效假设登录失败是错误 。然而,并非总是如此。
User?
相同。更像是编写自定义可选枚举,最终都会使调用者变得混乱。此外,它仅在登录进程同步时才有效。 这是另一种选择:
func login(with login: Login, failure: ((LoginError) -> ())?, success: (User) -> ()?) {
if successful {
success?(user)
} else {
failure?(customError)
}
}
// Rename with exactly how this handles the error if you'd have more handlers,
// Document the existence of this handler, so caller can pass it along if they wish to.
func handleLoginError(_ error: LoginError) {
// Error handling
}
现在来电者可以;只是决定忽略错误或传递处理函数/闭包。
login(with: Login("email", "password"), failure: nil) { user in
// Ignores the error
}
login(with: Login("email", "password"), failure: handleLoginError) { user in
// Lets the error be handled by the "default" handler.
}
PS,为相关领域创建数据结构是一个好主意; Login
电子邮件和密码,而不是单独设置属性。
struct Login {
typealias Email = String
typealias Password = String
let email: Email
let password: Password
}