Alamofire
設計了2種與Request
相對應的Response
類型,他們分別是:json
DefaultDataResponse / DataResponse
-- >DataRequest
,UploadRequest
DefaultDownloadResponse / DataResponse
--> DownloadRequest
response
方法,返回的就是帶有Default開頭的響應者,好比DefaultDataResponse
,DefaultDownloadResponse
。response
方法,返回的就是DataResponse
或者DataResponse
。DefaultDataResponse
/ DataResponse
來舉例,DataResponse
基本上只比DefaultDataResponse
多了一個系列化後的數據屬性。先看一段簡單代碼swift
SessionManager.default
.request(urlString)
.response { (response) in
print(response)
}
.responseJSON { (jsonResponse) in
print(jsonResponse)
}
複製代碼
Alamofire
是採用的鏈式調用設計,因此能夠在調用response
後還能繼續調用responseJSON
。能實現鏈式訪問的原理就是每一個函數的返回值都是Self
。request
,再調用了response
。那麼Alamofire
是怎麼保證response
的的執行時機是在request
發起請求並在數據回調以後再執行的呢?這裏必定有貓膩,要否則只要調用了response
方法就會裏面執行裏面的代碼。進入到response
方法裏看看: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
}
複製代碼
response
加到了一個隊列queue
中self.queue = {
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = 1
operationQueue.isSuspended = true
operationQueue.qualityOfService = .utility
return operationQueue
}()
複製代碼
operationQueue.maxConcurrentOperationCount = 1
說明是一個串行隊列operationQueue.isSuspended = true
隊列默認是掛起狀態response
方法時把任務加到隊列queue
中queue
是一個串行隊列,而且默認是掛起狀態,因此先不執行任務queue.isSuspended = false
,開始執行隊列中的任務。func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let taskDidCompleteWithError = taskDidCompleteWithError {
taskDidCompleteWithError(session, task, error)
} else {
// 省略無關代碼......
queue.isSuspended = false
}
}
複製代碼
把目光移到response
方法,建立了一個DefaultDataResponse
對象並做爲completionHandler
的參數回調出去。api
public struct DefaultDataResponse {
/// 表示該響應來源於那個請求
public let request: URLRequest?
/// 服務器返回的響應
public let response: HTTPURLResponse?
/// 響應數據
public let data: Data?
/// 在請求中可能發生的錯誤
public let error: Error?
/// 請求的時間線封裝
public let timeline: Timeline
/// 包含了請求和響應的統計信息
var _metrics: AnyObject?
}
複製代碼
DefaultDataResponse
是一個結構體類型,用來保存數據。通常來講,在Swift
中,若是隻是爲了保存數據,那麼應該把這個類設計成struct
。struct
是值傳遞,所以對數據的操做更安全。Response
的數據所有保存在DefaultDataResponse
結構體中,化零爲整,很好的一個面向對象的設計原則,把這個完整的數據返回給用戶,用戶想用什麼就取什麼。DefaultDataResponse
中的data
是如何來的。繼續來到response
方法中:var dataResponse = DefaultDataResponse(
request: self.request,
response: self.response,
data: self.delegate.data,
error: self.delegate.error,
timeline: self.timeline
)
複製代碼
DataTaskDelegate
裏的data
,發現其實返回的是mutableData
,那麼mutableData
又是什麼呢?override var data: Data? {
if dataStream != nil {
return nil
} else {
return mutableData
}
}
複製代碼
func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
if initialResponseTime == nil { initialResponseTime = CFAbsoluteTimeGetCurrent() }
if let dataTaskDidReceiveData = dataTaskDidReceiveData {
dataTaskDidReceiveData(session, dataTask, data)
} else {
if let dataStream = dataStream {
dataStream(data)
} else {
mutableData.append(data)
}
// 省略無關代碼......
}
}
複製代碼
mutableData
中。DataResponse<Value>
比上邊的DefaultDataResponse
多了一個public let result: Result<Value>
屬性,該屬性存儲了序列化後的數據。接着看看在Alamofire
中是如何使用Result
的,來到responseJSON
方法中:安全
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
)
}
複製代碼
JSON
再返回,completionHandler
函數的參數類型爲DataResponse<Any>
,其中的Any
就會傳遞給Result
,也就是Result<Any>
。通常來講,咱們須要對response.data
作序列化處理以後才方便使用。Alamofire
已經提供了一些經常使用的序列化器,能夠直接調用api使用。一樣也能夠自定義序列化器來實現本身功能。下面來看看responseJSON
方法時怎麼實現的。服務器
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
方法,只是傳了一個json
序列化器做爲參數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)
}
}
複製代碼
DataResponseSerializer
結構體,而且保存了一個尾隨閉包serializeResponse
。Response
流程分析能夠知道,當請求完成回調以後代碼會執行到response
方法中加入到隊列的任務。也就會調用上面的尾隨閉包。Request.serializeResponseJSON
方法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)))
}
}
複製代碼
Result<Any>
類型的枚舉,若是有錯誤信息,就返回return .failure(error!)
並把錯誤信息作完枚舉的關聯值返回出去。return .success(json)
。dataResponse.result
來判斷請求結果成功仍是失敗。response
方法的響應結果回調completionHandler(dataResponse)
加入到一個串聯隊列,而且這個隊列是默認掛起的,當請求完成後隊列開始執行,這樣才能保證是在請求完成以後再回調結果。DataResponseSerializerProtocol
這個協議就能夠。DataResponse
幫助咱們統一管理請求過程當中的數據,請求成功、失敗、時間軸等等,便於業務層處理。有問題或者建議和意見,歡迎你們評論或者私信。 喜歡的朋友能夠點下關注和喜歡,後續會持續更新文章。session