Swift 网络请求封装
网络请求封装主要利用 Swift 的 protocol 和 enum 特性
定义一个protocol, 用于规范网络请求接口
/// 接口类型
protocol TargetType {
/// 接口地址
var serviceAddress: String { get }
/// 参数信息
var parameters: [String: Any]? { get }
/// 请求类型
var method: HTTPMethod { get }
}
HTTPMethod由Alamofire定义如下:
public enum HTTPMethod: String {
case options = "OPTIONS"
case get = "GET"
case head = "HEAD"
case post = "POST"
case put = "PUT"
case patch = "PATCH"
case delete = "DELETE"
case trace = "TRACE"
case connect = "CONNECT"
}
以订单列表和订单详情请求做声明举例
以一个 enum 实现 TargetType protocol,巧妙运用 swift 可以在 enum 自生做 switch case 操作
enum OrderTarget: TargetType {
/// 订单列表接口
case orders(uid: Int)
/// 订单详情接口
case detail(no: String)
// MARK: - 参数说明
var serviceAddress: String {
switch self {
case .orders:
return "orders"
case let .detail(no):
return "orders/\(no)"
}
}
var parameters: [String : Any]? {
switch self {
case let .orders(uid):
return ["uid": uid]
default:
return nil
}
}
var method: HTTPMethod {
switch self {
default:
return .get
}
}
}
网络请求封装
网络请求采用了 Alamofire、AlamofireObjectMapper、ObjectMapper、SwiftyJSON
import Foundation
import AlamofireObjectMapper
import ObjectMapper
// 请求地址前缀
private let kBaseURL = "***"
/// 超时时长
private let kTimeoutIntervalForRequest: TimeInterval = 15
/// 服务器返回的对象封装,根据实际情况定义
struct Response: Mappable, CustomStringConvertible {
var status: Int?
var code: Int?
var message: String?
var result: [String: Any]?
var reason: String?
var stack: String?
init?(map: Map) {}
mutating func mapping(map: Map) {
status <- map["status"]
code <- map["code"]
message <- map["message"]
result <- map["result"]
reason <- map["reason"]
stack <- map["stack"]
}
public var description: String {
return "status: \(String(describing: status))\n message: \(String(describing: message))\n result: \(String(describing: result))"
}
}
/// 错误类型
///
/// - netError: 网络异常
/// - serverError: 服务器异常 500
/// - sessionError: 用户未授权(签名错误或无权限)
/// - nodataError: 没有数据
/// - otherError: 其他错误
enum NetworkError: CustomStringConvertible {
case netError(String)
case serverError(String)
case sessionError(String)
case nodataError(String)
case otherError(String)
public var description: String {
switch self {
case let .netError(text):
return text
case let .serverError(text):
return text
case let .nodataError(text):
return text
case let .sessionError(text):
return text
case let .otherError(text):
return text
}
}
}
/// 封装返回结果
///
/// - success: 成功结果
/// - error: 错误结果
enum NetworkResult {
case success(Response)
case error(NetworkError)
}
/// 网络请求
struct Network: RequestAdapter {
static let `default`: Network = {
let network = Network()
network.sessionManager.adapter = network
return network
}()
private let sessionManager: SessionManager = {
let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = kTimeoutIntervalForRequest
let sessionManager = SessionManager(configuration: config)
return sessionManager
}()
public func adapt(_ urlRequest: URLRequest) throws -> URLRequest {
return urlRequest
}
/// 发出请求
///
/// - target: 请求目标,包含方法信息和参数信息
/// - completionHandler: 结果回调
/// - Returns: DataRequest 实例
func request(target: TargetType,
completionHandler: @escaping (NetworkResult) -> Void) -> Request {
let url = kBaseURL + target.serviceAddress
var headers = SessionManager.defaultHTTPHeaders
// 请求头处理...
let request = self.sessionManager.request(url,
method: target.method,
parameters: target.parameters,
encoding: URLEncoding.default,
headers: headers)
return request.responseJSON { (originalResponse) in
self.dealResponse(originalResponse: originalResponse, completionHandler: completionHandler)
}
}
/// 统一处理响应结果
///
/// - Parameters:
/// - originalResponse: 原始请求
/// - completionHandler: 成功回调
private func dealResponse(originalResponse: DataResponse<Any>,
completionHandler: @escaping (NetworkResult) -> Void) {
if let url = originalResponse.response?.url?.absoluteString {
print("请求地址:\(url)")
}
let statusCode = originalResponse.response?.statusCode ?? -1
// 根据自己的逻辑对结果判断
switch originalResponse.result {
case let .success(value):
let json = JSON(value)
print("\(statusCode) 返回结果:\(json)")
var resp = Response(JSON: json.dictionaryObject!)!
if statusCode == 401 {
let msg = resp.message ?? "登录信息失效"
if resp.code == 40006 {
completionHandler(.error(.otherError(msg)))
} else {
// 此处可以做全局通用的登录失效提示如:
/*
DispatchQueue.main.async {
HUD.showError(text: resultError.description)
}
*/
}
completionHandler(.error(.sessionError(msg)))
return
} else if statusCode == 422 {
completionHandler(.error(.otherError(resp.msg ?? "请求参数错误")))
return
} else if statusCode == 400 || statusCode == 403 || statusCode == 404 {
completionHandler(.error(.otherError(resp.msg ?? "请求失败")))
return
} else if statusCode == 500 {
completionHandler(.error(.otherError(resp.msg ?? "服务器异常")))
return
} else {
completionHandler(.success(resp))
}
break
case let .failure(error):
let description = error.localizedDescription
print("\(statusCode) 错误信息:\(description)")
if description == "已取消" {
return
}
let resultError: NetworkError = .netError(description)
completionHandler(.error(resultError))
// 此处可以做全局通用的网络异常提示,如:
/*
DispatchQueue.main.async {
HUD.showError(text: resultError.description) // 弹出全局通用错误提示
}
*/
break
}
}
}
网络请求调用示例
let request = Network.default.request(target: OrderTarget.detail(no: "1111"))
{ [unowned self] (result) in
switch result {
case let .success(resp):
// 成功处理...
break
case let .error(error):
// 错误处理...
switch error {
case let .otherError(text):
// CRHUD.showToast(text)
break
default:
break
}
break
}
}