在上两篇中研究了下Alamofire的请求发起过程以及在请求发起过程中一些有用的功能,本篇来看看数据接受的环节
response
如何接受响应?
Alamofire
采用一种链式编程的语法糖,极大地方便调用.来看一段有意思的代码.
SessionManager.default
.request(urlString)
.response { (response:DefaultDataResponse) in
debugPrint(response)
}.responseData { (response:DataResponse<Data>) in
debugPrint(response)
}.responseJSON { (response:DataResponse<Any>) in
debugPrint(response)
}.responsePropertyList { (response:DataResponse<Any>) in
debugPrint(response)
}
- 上面的代码把
Alamofire
对外提供的几种最简形式的数据接受方法都串联起来了. - 回调的顺序而且是从
上到下的顺序
,本文的内容会解释原因
为何可以连续调用response 相关方法?
为了节省篇幅,部分方法只值列出了方法定义
open class SessionManager {
public static
let `default`: SessionManager = {
let configuration = URLSessionConfiguration.default
configuration.httpAdditionalHeaders = SessionManager.defaultHTTPHeaders
return SessionManager(configuration: configuration)
}()
private func
request(_ urlRequest: URLRequest?, failedWith error: Error) -> DataRequest
}
extension DataRequest {
public func
response(queue: DispatchQueue? = nil,
completionHandler: @escaping (DefaultDataResponse) -> Void)
-> Self
public func
responseData(
queue: DispatchQueue? = nil,
completionHandler: @escaping (DataResponse<Data>) -> Void)
-> Self
public func
responseJSON(
queue: DispatchQueue? = nil,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (DataResponse<Any>) -> Void)
-> Self
public func
responsePropertyList(
queue: DispatchQueue? = nil,
options: PropertyListSerialization.ReadOptions = [],
completionHandler: @escaping (DataResponse<Any>) -> Void)
-> Self
}
-
SessionManager.default
调用之后得到 SessionManager 单例对象. - 调用
SessionManager
的request
方法之后得到DataRequest
对象 - 调用
DataRequest
的reponse
,responseJSON
,reponseData
,responsePropertyList
返回的都是DataRequest
对象,所以responseXXX
方法可以连续调用.
response 系列方法干了啥?
以 response
和 responseJSON
方法为例,来看看源代码
extension DataRequest {
public func response(queue: DispatchQueue? = nil, completionHandler: @escaping (DefaultDataResponse) -> Void) -> Self {
delegate.queue.addOperation {
(queue ?? DispatchQueue.main).async {
var dataResponse = DefaultDataResponse(
request: self.request,
response: self.response,
data: self.delegate.data,
error: self.delegate.error,
timeline: self.timeline
)
dataResponse.add(self.delegate.metrics)
completionHandler(dataResponse)
}
}
return self
}
public func responseJSON(
queue: DispatchQueue? = nil,
options: JSONSerialization.ReadingOptions = .allowFragments,
completionHandler: @escaping (DataResponse<Any>) -> Void)
-> Self
{
return response(
queue: queue,
responseSerializer: DataRequest.jsonResponseSerializer(options: options),
completionHandler: completionHandler
)
}
//response 方法2
public func response<T: DataResponseSerializerProtocol>(
queue: DispatchQueue? = nil,
responseSerializer: T,
completionHandler: @escaping (DataResponse<T.SerializedObject>) -> Void)
-> Self
{
delegate.queue.addOperation {
let result = responseSerializer.serializeResponse(
self.request,
self.response,
self.delegate.data,
self.delegate.error
)
var dataResponse = DataResponse<T.SerializedObject>(
request: self.request,
response: self.response,
data: self.delegate.data,
result: result,
timeline: self.timeline
)
dataResponse.add(self.delegate.metrics)
(queue ?? DispatchQueue.main).async { completionHandler(dataResponse) }
return self
}
}
open class TaskDelegate: NSObject {
init(task: URLSessionTask?) {
_task = task
self.queue = {
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 1
operationQueue.isSuspended = true
operationQueue.qualityOfService = .utility
return operationQueue
}()
}
}
response
方法 首先用queue
参数把我们传进去的completionHanlder 闭包
包装进了一个任务,在这个任务中,创建了一个DefaultDataResponse
对象,这个对象保存了一些信息, 然后把这个DefaultResponse
对象传递给completionHandler 闭包
. 然后又把这个任务添加到了delegate.queue
中,delegate.queue
我在 Alamofire 网络请求流程探索2
中提到过,这里也放出了源代码,delagate.queue
是一个初始状态为挂起的串行队列. 之后返回自身. 当一次请求结束后,deleage.queue
会结束挂起状态这时所有被添加的任务都会顺序执行,这也是为什么打印顺序是从上至下的原因responsJSON
方法是一个装饰方法,它转而调用了 另一个参数更多的response
方法. 值得注意的是多传递了一个参数DataRequest.jsonResponseSerializer(options: options)
response 方法2
(姑且这么叫吧😂)相比上面的response
方法 关联了泛型T: DataResponseSerializerProtocol
,并且多了 类型为T
的参数responseSerializer
response 方法2
的实现 与response
方法 大同小异.
1.传递给completionHandler闭包
的参数变成了DataResponse<T.serializedObject>
类型
2.调用了responseSerializer.serializeResponse
方法,得到了result
,将result
传递给了DataResponse
.
由此可见DataRequest.jsonResponseSerializer(options: options)
方法以及 DataResponseSerializerProtocol
协议一定做了一些操作.
//该协议定义序列化操作结果接口
public protocol DataResponseSerializerProtocol {
associatedtype SerializedObject
var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<SerializedObject> { get }
}
extension DataRequest {
public static func jsonResponseSerializer(
options: JSONSerialization.ReadingOptions = .allowFragments)
-> DataResponseSerializer<Any>
{
return DataResponseSerializer { _, response, data, error in
return Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
}
}
}
public struct DataResponseSerializer<Value>: DataResponseSerializerProtocol {
public typealias SerializedObject = Value
public var serializeResponse: (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>
public init(serializeResponse: @escaping (URLRequest?, HTTPURLResponse?, Data?, Error?) -> Result<Value>) {
self.serializeResponse = serializeResponse
}
}
extension Request {
public static func serializeResponseJSON(
options: JSONSerialization.ReadingOptions,
response: HTTPURLResponse?,
data: Data?,
error: Error?)
-> Result<Any>
{
guard error == nil else { return .failure(error!) }
if let response = response, emptyDataStatusCodes.contains(response.statusCode) { return .success(NSNull()) }
guard let validData = data, validData.count > 0 else {
return .failure(AFError.responseSerializationFailed(reason: .inputDataNilOrZeroLength))
}
do {
let json = try JSONSerialization.jsonObject(with: validData, options: options)
return .success(json)
} catch {
return .failure(AFError.responseSerializationFailed(reason: .jsonSerializationFailed(error: error)))
}
}
}
public enum Result<Value> {
case success(Value)
case failure(Error)
/// Returns `true` if the result is a success, `false` otherwise.
public var isSuccess: Bool {
switch self {
case .success:
return true
case .failure:
return false
}
}
/// Returns `true` if the result is a failure, `false` otherwise.
public var isFailure: Bool {
return !isSuccess
}
/// Returns the associated value if the result is a success, `nil` otherwise.
public var value: Value? {
switch self {
case .success(let value):
return value
case .failure:
return nil
}
}
/// Returns the associated error value if the result is a failure, `nil` otherwise.
public var error: Error? {
switch self {
case .success:
return nil
case .failure(let error):
return error
}
}
}
DataRequest.jsonResponseSerializer(options: options)
方法中返回了一个遵循DataResponseSerializerProtocol
的结构体DataResponseSerializer<Value>
,在初始化闭包中,调用了Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
方法,进行实际JSON序列化操作,并且把实例化的结果传递给Result枚举.用
DataResponseSerializer<Value>
进行包装调用Request.serializeResponseJSON
方法的过程 ,来符合面向协议编程的思想.
自定义序列化
在实际的开发过程中,我们希望给外界使用的是已经能直接使用的model
,能否通过自定义序列化过程满足我们的需求?
答案是肯定的,模仿上文中responseJSON
的实现方式.
//定义创建序列化对象的统一协议,用于序列化对象
protocol YourObjectSerializableProtocol {
init?(response: HTTPURLResponse)
}
//模型数据
struct User:YourObjectSerializableProtocol {
var name :String?
init?(response: HTTPURLResponse) {
name = "aaa"
}
}
//扩展DataRequest 提供一个 responseObject 方法,该方法支持泛型<T:YourObjectSerializableProtocol>
extension DataRequest {
@discardableResult
func responseObject<T:YourObjectSerializableProtocol> (queue:DispatchQueue? = nil,completionHandler:@escaping ((DataResponse<T>) -> Void)) -> Self {
let responseSerializer = DataResponseSerializer<T>{
requset,response,data,error in
guard error == nil else {return .failure(NSError(domain: "your domain", code: 0000, userInfo: nil))}
guard let response = response,let responseObject = T(response: response) else {
return .failure(NSError(domain:"your domain", code: 0000, userInfo: nil))
}
return .success(responseObject)
}
return response(
queue: queue,
responseSerializer: responseSerializer,
completionHandler: completionHandler
)
}
}
//外界调用
SessionManager.default
.request(urlString)
.responseObject { (response : DataResponse<User>) in
debugPrint(response)
}
- 首先定义创建序列化对象的统一协议
YourObjectSerializableProtocol
,提供了一个init
方法用来序列化对象 - 扩展
DataRequest
提供一个responseObject
方法,将我们自定义的序列化流程添加进去 - 外界调用时,直接指定泛型
T
为我们的User
.