网络请求是 App 中最经常使用的更能之一,除了 Apple 提供的 URLSession 以外,还有对其进行封装,功能更增强的的 Alamofire等强大的工具,尽管这样,咱们依然会在本身的 App 中封装一套网络请求工具,以达到作网络请求时,代码简洁高效.html
作网络请求的时候尽可能的简单,只须要少许的代码便可处理返回的数据git
enum RequestMethod {
case post
case get
}
///请求对象
struct Requset {
init(method: RequestMethod = .post, baseURL: String = "", path: String, parameters: [String : Any]?){
self.method = method
self.baseURL = baseURL
self.path = path
self.parameters = parameters ?? [:]
}
var method: RequestMethod
var baseURL: String
var path: String
var parameters: [String: Any]
}
///网络工具
class NetworkManager {
static let shared = NetworkManager("")
init(_ baseURL: String = "") {
self.baseUrl = baseURL
}
var baseUrl = ""
func post(path: String,params: [String: Any]?,result: @escaping ((Result<Data,Error>)->())){
let request = Requset(baseURL:baseUrl, path: path, parameters: params)
let target = Target(request: request)
self.request(target: target, result: result)
}
func get(path: String,params: [String: Any]?,result: @escaping ((Result<Data,Error>)->())){
let request = Requset(baseURL:baseUrl, path: path, parameters: params)
let target = Target(request: request)
self.request(target: target, result: result)
}
private func request(target: Target,result: @escaping ((Result<Data,Error>)->())) {
MoyaProvider<Target>().request(target) { (res) in
switch res {
case .success(let a):
result(.success(a.data))
case .failure:
result(.failure(res.error!))
}
}
}
}
复制代码
如今已经能够作网络请求了,好比:把百度首页数据请求下来github
NetworkManager("https://www.baidu.com").get(path: "", params: nil) { (res) in
let data = try! res.get()
print(String(data: data, encoding: .utf8))
}
复制代码
Optional("\r\n\r\n\r\n\r\n <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">\r\n <meta http-equiv="content-type" content="text/html;charset=utf-8">\r\n <meta content="always" name="referrer">\r\n <script src="ss1.bdstatic.com/5eN1bjq8AAU…">\r\n
页面不存在_百度搜索 \r\n ....chrome
仅仅这样封装很明显不可以达到精简的目的,这样其实和直接使用 Alamofire 没啥区别.json
通常后台返回的数据都有固定的格式,好比:api
{
"msg": "请求成功",
"code": 1001,
"data": {...}
}
或者:
{
"msg": "请求成功",
"code": 1001,
"data": [...]
}
复制代码
将其转换成对应的模型:bash
public struct DataResponse<T> {
public init (){}
public var code: Int = -1
public var msg: String = ""
public var data: T?
}
public struct ListResponse<T> {
public init (){}
public var code: Int = -1
public var msg: String = ""
public var data: [T] = []
}
复制代码
咱们实现一个 Protocol 继承自 HandyJSON (HandyJSON自己也是协议),而后是咱们的 Response 遵照这个协议.网络
public protocol RequestProtocol: HandyJSON {
static func request(api: API, params: [String: Any]?, result: ((ResponseResult<Self>)->())?)
}
public extension RequestProtocol where Self: HandyJSON {
static func request(api: API, params: [String: Any]?, result: ((ResponseResult<Self>)->())?) {
let completionHandle: ((Result<Data,Error>)->()) = { res in
switch res {
case .success(let data):
let jsonStr = String(data: data, encoding: .utf8)
#if DEBUG
print("url: \(api.path)")
print("response:")
print(jsonStr ?? "")
#endif
///不是 json 数据,抛出 json 解析失败错误
guard let jsonObj = self.self.deserialize(from: jsonStr) else {
result?(.failure(.deserializeFailed))
return
}
result?(.success(jsonObj))
case .failure(_):
///处理错误 抛出去
result?(.failure(.requestFailed))
}
}
if api.method == .post {
NetworkManager.shared.post(path: api.path, params: params, result: completionHandle)
}else{
NetworkManager.shared.get(path: api.path, params: params, result: completionHandle)
}
}
}
复制代码
而后久能够以下优雅的作请求:ide
NetworkManager.shared.baseUrl = "https://api.douban.com"
BookResponse.request(api: .getBookDetail, params: nil) { (res) in
guard res.isSuccess else { return }
print(res.value?.toJSON())
}
复制代码
{"msg":"invalid_apikey","code":104,"request":"POST /v2/book/1220562"}工具
API 是这么样的结构体
public struct API {
var path: String
var method: RequestMethod
init(path: String, method: RequestMethod = .post) {
self.path = path
self.method = method
}
}
///能够经过这种方式 减小硬编码可能会带来的错误
extension API {
static let getBookDetail = API(path: "/v2/book/1220562")
}
复制代码