我正在处理用户需要登录的应用。 Web应用程序使用令牌,用户可以使用其用户名和密码调用Web服务。我现在的问题是可能发生的句柄错误的最佳方式。我现在拥有的:
LoginViewController.swift
self.api.token(forUsername: "a", password: "b") { (result) in
switch (result) {
case .failure(let error):
print("something when wrong \(error)")
case .success(let token):
print("token \(token)")
}
使用https://github.com/3lvis/Networking
登录APIClient(self.api)class LoginAPIClient {
enum ResponseError: Error {
case unexpectedDataError
case unknownError
}
enum Result {
case success(String)
case failure(Error)
}
lazy var networking: Networking = {
let networking = Networking(baseURL: APIClient.serverURL())
return networking
}()
func token(forUsername username: String, password: String, completion: @escaping (Result) -> Void) {
let parameters = ["username" : username, "password" : password]
networking.post("/api/login", parameters: parameters) { (result) in
switch result {
case .failure(let response):
return completion(.failure(response.error))
case .success(let response):
if var token = response.headers["Authorization"] as? String {
token = token.replacingOccurrences(of: "Bearer ", with: "")
return completion(.success(token))
}
return completion(.failure(ResponseError.unknownError))
}
}
}
}
例如,我在创建自己的错误return completion(.failure(ResponseError.unknownError))
时,如果服务器以成功的状态代码(200)响应,但不知何时响应中缺少Authorization标头。
这是有效的,唯一的问题是现在当我处理ViewController中的错误时,我不知道它失败的确切原因。例如,从网络库我得到一个错误代码(400或401等),但这丢失了,因为它首先是一个NSError。我可以使用NSError,但不知怎的,这感觉不对。有人能指出我正确的方向吗?
我想到的解决方案之一是添加一个额外的枚举,然后做这样的事情:
enum Result {
case success(String)
case networkFailure(FailureJSONResponse)
case failure(Error)
}
self.api.token(forUsername: "a", password: "b") { (result) in
switch (result) {
case .failure(let error):
print("something when wrong \(error)")
case .networkFailure(let response):
print("something when wrong \(error)")
case .success(let token):
print("token \(token)")
}
但我在转换中只有1次成功和1次失败。
答案 0 :(得分:3)
每个应用程序通常都有自己的“错误”,因此在您的情况下,您可以定义
public enum AppError: Swift.Error, CustomStringConvertible {
case networkError(code: Int)
case anotherError(message: String?)
case underlying(Swift.Error)
public var description: String {
switch self {
case .networkError(let code):
return "Network error with code \(code)"
default://I'm not gonna cover all cases, but you should :)
return "Error"
}
}
}
然后你可以使用你的方法
enum Result {
case success(String)
case failure(AppError)
}
答案 1 :(得分:0)
您可以将第二个参数添加到completion
块:
func token(forUsername username: String, password: String, completion: @escaping (Result, error: ResponseError?) -> Void)