封装 一个面向协议的网络请求
Bamboots 是基于 Alamofire
的一系列扩展库,这个库 充分的体现了 面向 Protocol
编程在组合设计模式中的应用。
目前我对 network request
的希望是: 传入一个请求体:form
,然后给我返回: 成功后的模型对象、失败后的 error
对象
let form = WeatherForm<RootModel>()
request(
form,
success: { (response) in
print(response.data.three_day_forecast.count)
}) { (error) in
print(error.localizedDescription)
}
当我们也可以根据需要来处理结果,有时候我们对请求成功后的结果感兴趣,有时候我们需要对请求失败后的 error
做特殊处理:
func request<T: Codable>(
_ form: WeatherForm<T>,
success: ((T) -> Void)? = nil ,
failure: ((_ error: Error) -> Void)? = nil
)
如上的接口就能满足我们的需要,我们的 form
提供了所有的请求信息, success
、 failure
两个闭包就是我们可以根据当前网络请求的需要来进行处理了。当然我们对应的闭包传入 nil
或做缺省处理,这样就会使用我们的默认实现了。然后在默认实现里统一处理相关信息,当然这也是工程的一部分了,需要根据具体项目而定了。让我们看一下 WeatherForm<RootModel>()
这个表单里面携带了我们网络请求的一些条件信息,包括: api
、method
、hearders
、parameters
, 还有我们需要返回的模型类型RootModel
。这些信息中有些是高频修改的,如 api
、method
、parameters
,对于 api
、method
我们通过 enum
统一管理,对于 parameters
我们则通过属性做map
来简化请求参数的赋值, 而对于 hearders
这种修改频率低的我们可以做统一处理,在需要修改时再添加extension
实现, 如:
extension Formable {
public func headers() -> [String: String] {
return ["accessToken": "xxx"]
}
}
extension Formable where Self: RequestFormable {
public func headers() -> [String: String] {
return [
"accessToken": "xxx", "fileName": "xxx",
"App-Source": "APP",
"User-Os": "iOS",
]
}
}
extension Formable where Self: UploadFormable {
public func headers() -> [String: String] {
return ["accessToken": "xxx", "fileName": "xxx"]
}
}
这里的 WeatherForm<RootModel>()
继承了 GetForm
当然以上这些是基于 Bamboots
而封装的。我们的 Bamboots
在 Swift 3
时是基于 AlamofireObjectMapper
的,当然这在 Swift 4
中, 我们取而代之使用的就是 AlamofireCodable, 从命名上就可以看出来,功能是一样的,只是在 Swift 4
中我们有了 Codable
我们就可以祛除ObjectMapper
了,也许不久我们直接就可以在 Alamofire 看到相应的实现了,
此图为证。
AlamofireCodable
在 Alamofire
的基础上为DataRequest
添加了两个扩展函数:
/// Adds a handler to be called once the request has finished.
///
/// - Parameters:
/// - queue: The queue on which the completion handler is dispatched.
/// - keyPath: The key path where object mapping should be performed
/// - completionHandler: A closure to be executed once the request has finished and the data has been decoded by JSONDecoder.
/// - Returns: The request.
@discardableResult
public func responseObject<T: Codable>(queue: DispatchQueue? = nil, keyPath: String? = nil, completionHandler: @escaping (DataResponse<T>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectSerializer(keyPath), completionHandler: completionHandler)
}
通过调用 responseObject
直接在回调中返回含有T
对象的DataResponse<T>
,而下面这个函数
/// Adds a handler to be called once the request has finished. T: Codable
///
/// - Parameters:
/// - queue: The queue on which the completion handler is dispatched.
/// - keyPath: The key path where object mapping should be performed
/// - completionHandler: A closure to be executed once the request has finished and the data has been decoded by JSONDecoder.
/// - Returns: The request.
@discardableResult
public func responseArray<T: Codable>(queue: DispatchQueue? = nil, keyPath: String? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectArraySerializer(keyPath), completionHandler: completionHandler)
}
则提供了对数组的支持。