封装 一个面向协议的网络请求
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)
}
则提供了对数组的支持。