在上兩篇中研究了下Alamofire的請(qǐng)求發(fā)起過(guò)程以及在請(qǐng)求發(fā)起過(guò)程中一些有用的功能,本篇來(lái)看看數(shù)據(jù)接受的環(huán)節(jié)
response
如何接受響應(yīng)?
Alamofire
采用一種鏈?zhǔn)骄幊痰恼Z(yǔ)法糖,極大地方便調(diào)用.來(lái)看一段有意思的代碼.
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
對(duì)外提供的幾種最簡(jiǎn)形式的數(shù)據(jù)接受方法都串聯(lián)起來(lái)了. - 回調(diào)的順序而且是從
上到下的順序
,本文的內(nèi)容會(huì)解釋原因
為何可以連續(xù)調(diào)用response 相關(guān)方法?
為了節(jié)省篇幅,部分方法只值列出了方法定義
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
調(diào)用之后得到 SessionManager 單例對(duì)象. - 調(diào)用
SessionManager
的request
方法之后得到DataRequest
對(duì)象 - 調(diào)用
DataRequest
的reponse
,responseJSON
,reponseData
,responsePropertyList
返回的都是DataRequest
對(duì)象,所以responseXXX
方法可以連續(xù)調(diào)用.
response 系列方法干了啥?
以 response
和 responseJSON
方法為例,來(lái)看看源代碼
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
參數(shù)把我們傳進(jìn)去的completionHanlder 閉包
包裝進(jìn)了一個(gè)任務(wù),在這個(gè)任務(wù)中,創(chuàng)建了一個(gè)DefaultDataResponse
對(duì)象,這個(gè)對(duì)象保存了一些信息, 然后把這個(gè)DefaultResponse
對(duì)象傳遞給completionHandler 閉包
. 然后又把這個(gè)任務(wù)添加到了delegate.queue
中,delegate.queue
我在 Alamofire 網(wǎng)絡(luò)請(qǐng)求流程探索2
中提到過(guò),這里也放出了源代碼,delagate.queue
是一個(gè)初始狀態(tài)為掛起的串行隊(duì)列. 之后返回自身. 當(dāng)一次請(qǐng)求結(jié)束后,deleage.queue
會(huì)結(jié)束掛起狀態(tài)這時(shí)所有被添加的任務(wù)都會(huì)順序執(zhí)行,這也是為什么打印順序是從上至下的原因responsJSON
方法是一個(gè)裝飾方法,它轉(zhuǎn)而調(diào)用了 另一個(gè)參數(shù)更多的response
方法. 值得注意的是多傳遞了一個(gè)參數(shù)DataRequest.jsonResponseSerializer(options: options)
response 方法2
(姑且這么叫吧??)相比上面的response
方法 關(guān)聯(lián)了泛型T: DataResponseSerializerProtocol
,并且多了 類型為T
的參數(shù)responseSerializer
response 方法2
的實(shí)現(xiàn) 與response
方法 大同小異.
1.傳遞給completionHandler閉包
的參數(shù)變成了DataResponse<T.serializedObject>
類型
2.調(diào)用了responseSerializer.serializeResponse
方法,得到了result
,將result
傳遞給了DataResponse
.
由此可見(jiàn)DataRequest.jsonResponseSerializer(options: options)
方法以及 DataResponseSerializerProtocol
協(xié)議一定做了一些操作.
//該協(xié)議定義序列化操作結(jié)果接口
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)
方法中返回了一個(gè)遵循DataResponseSerializerProtocol
的結(jié)構(gòu)體DataResponseSerializer<Value>
,在初始化閉包中,調(diào)用了Request.serializeResponseJSON(options: options, response: response, data: data, error: error)
方法,進(jìn)行實(shí)際JSON序列化操作,并且把實(shí)例化的結(jié)果傳遞給Result枚舉.用
DataResponseSerializer<Value>
進(jìn)行包裝調(diào)用Request.serializeResponseJSON
方法的過(guò)程 ,來(lái)符合面向協(xié)議編程的思想.
自定義序列化
在實(shí)際的開(kāi)發(fā)過(guò)程中,我們希望給外界使用的是已經(jīng)能直接使用的model
,能否通過(guò)自定義序列化過(guò)程滿足我們的需求?
答案是肯定的,模仿上文中responseJSON
的實(shí)現(xiàn)方式.
//定義創(chuàng)建序列化對(duì)象的統(tǒng)一協(xié)議,用于序列化對(duì)象
protocol YourObjectSerializableProtocol {
init?(response: HTTPURLResponse)
}
//模型數(shù)據(jù)
struct User:YourObjectSerializableProtocol {
var name :String?
init?(response: HTTPURLResponse) {
name = "aaa"
}
}
//擴(kuò)展DataRequest 提供一個(gè) 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
)
}
}
//外界調(diào)用
SessionManager.default
.request(urlString)
.responseObject { (response : DataResponse<User>) in
debugPrint(response)
}
- 首先定義創(chuàng)建序列化對(duì)象的統(tǒng)一協(xié)議
YourObjectSerializableProtocol
,提供了一個(gè)init
方法用來(lái)序列化對(duì)象 - 擴(kuò)展
DataRequest
提供一個(gè)responseObject
方法,將我們自定義的序列化流程添加進(jìn)去 - 外界調(diào)用時(shí),直接指定泛型
T
為我們的User
.