enum 是封装中一个常用的方式,enum 可以与其他实例进行绑定的,我们可以让方法返回枚举类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public struct ErrorMetaData: Codable {
public var code: Int?
public var msg: String?
}
public enum NetworkResponseError: Error {
case error(errorData: ErrorMetaData)
case parsingError(error: Error?)
case requestFailed(error: Error?)
case badRequest(error: Error?)
case forbidden(error: Error?)
case serverError(error: Error?)
case redirected(error: Error?)
case migration(error: Error?)
}
比如请求成功,我们会首先check https 握手🤝是否成功,
通过switch 把error返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
private func checkStatusCode(with urlResponse: HTTPURLResponse, error: Error?) -> NetworkResponseError? {
switch urlResponse.statusCode {
case 200 ... 299: return nil
case 300 ... 399:
return NetworkResponseError.redirected(error: error)
case 403:
return NetworkResponseError.forbidden(error: error)
case 400 ... 499:
return NetworkResponseError.badRequest(error: error)
case 500 ... 509:
return NetworkResponseError.serverError(error: error)
default: return nil
}
}
我们可以正常通过 error?.localizedDescription
获取到错误信息,比如超时请重试等
但是往往我们后台没有和http绑定,我们需要在成功链接后,还需要check response里面的 code
和 message
// 200 but error in response
这个时候我们可以通过 extension
NetworkResponseError
重写 LocalizedError
的errorDescription
,code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
extension NetworkResponseError: LocalizedError {
public var errorDescription: String? {
switch self {
case let .parsingError(error),
let .requestFailed(error),
let .badRequest(error),
let .forbidden(error),
let .serverError(error),
let .redirected(error),
let .migration(error):
return error?.localizedDescription
case let .error(error):
return error.msg
}
}
public var code: Int? {
switch self {
case let .error(error):
return error.code
default:
return nil
break
}
}
}
在回调中我们可以 print
log
print(error?.localizedDescription ?? "no messages")
` if let error = error as? NetworkResponseError { print(error.code) } `
但在项目中会有些通用的error 处理,比如 强制退出,我们可以通过属性闭包来对其全局操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
private func handleSuccessResponse(with data: Data, and urlResponse: URLResponse?,
with completion: @escaping (R?, URLResponse?, NetworkResponseError?) -> Void) {
NetworkLayer.didFinishWithSuccess?()
if let urlRes = urlResponse?.url {
print("\n[NW]")
print("\nReceived: " + urlRes.description)
}
do {
if var responseObject = try? JSONDecoder().decode(ErrorMetaData.self, from: data) {
// 200 but error in response
if let code = responseObject.code {
if code == 0 || code == 200 {
if var result = try? JSONDecoder().decode(ResponseObject.self, from: data) {
print("[\nNW]")
print("[S] Reponse: \n" + ((convertToDict(result)?.description) ?? ""))
completion(result, urlResponse, nil)
}
} else {
print("\n[NW]\n")
print("[S] Error Response: code = " + "\(code)" + " msg = " + (responseObject.msg ?? "nil"))
if (responseObject.msg?.isEmpty ?? false) || responseObject.msg == nil {
responseObject.msg = "service error, try again later"
}
NetworkLayer.didExecuteWithError?(NetworkResponseError.error(errorData: responseObject))
completion(nil, nil, NetworkResponseError.error(errorData: responseObject))
}
}
}
} catch let error as Error {
print("[NW]")
print("JSONSerialization" + "\(error)")
completion(nil, nil, NetworkResponseError.parsingError(error: error))
}
}
我们在 NetworkLayer
定义几种闭包属性
1
2
3
4
5
6
public struct NetworkLayer {
public static var forceLogoutAction: (() -> Void)?
public static var didFinishWithSuccess: (() -> Void)?
public static var didFinishWithError: ((_ error: Error?) -> Void)?
public static var didExecuteWithError: ((_ error: Error?) -> Void)?
}
在appdelegate 中call setUpNetWorkLayer()
, 通过闭包来处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
extension AppDelegate {
@objc func setUpNetWorkLayer() {
NetworkLayer.forceLogoutAction = {
ApplicationFlow.sharedInstance().doLogout()
}
NetworkLayer.didFinishWithSuccess = {
}
NetworkLayer.didFinishWithError = { error in
print(error?.localizedDescription ?? "no messages")
}
NetworkLayer.didExecuteWithError = { error in
if let error = error as? NetworkResponseError {
print("error.localizedDescription" + "\(error.localizedDescription)")
if let code = error.code {
if code == 401 || code == 501 { // logout
NetworkLayer.forceLogoutAction?()
return
}
}
}
}
}
}