經過上一篇URlSession後臺下載,咱們已經知道了SessionManager
的做爲整個Alamofire
框架的核心樞紐的重要性🔐,還有一個比較重要的是SessionManager
的代理SessionDelegate
,封裝了URLSessionDelegate
。負責對Task
的回調事件提供默認實現(轉發給TaskDelegate
進行實際處理),而且以閉包的方式暴露給外部,讓外部能夠自定義實現。TaskDelegate
對URLSessionTask
的回調進行實際的處理,而且執行task
的完成回調用。Request
就 是對URLSessionTask
的封裝,是暴露給上層的請求任務。json
廢話很少說直接來用URLSession
建立一個request
和利用Alamofire
建立一個request
的例子🌰看看:swift
首先來看一個URLSession
的request
的用法:數組
guard let url = URL(string: "https://www.douban.com/j/app/radio/channels") else {
return;
}
let dataTask = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else{
return;
}
do{
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
}catch let error{
print(error)
}
};
dataTask.resume()
複製代碼
再來看一個基礎的Alamofire.request
用法:bash
Alamofire.request("https://www.douban.com/j/app/radio/channels").responseJSON { (response) in
if let JSONString = response.result.value {
print("JSONString: \(JSONString)")
}
}
複製代碼
有沒有以爲,若是使用系統的API
,咱們不得不先建立URL
,而後創建dataTask
,而且resume
,接着在callback
裏去解析JSON
。因爲Swift
是一種強類型的語言,咱們不得不進行大量的邏輯判斷和try-catch
🤦♂️。而Alamofire
把這些步驟簡化成了一個靜態的方法調用,而且用鏈式的方式來處理異步的Response
解析。因爲是鏈式的,咱們也能夠用鏈式的方式實現更多的邏輯。session
那麼在Alamofire.request
的內部具體作了什麼「騷」操做呢🤔?沒辦法🤷♀️️,想要看到內部實現,就要看到這裏的源碼,那麼就來吧...閉包
根據Alamofire.request
的這個方法,咱們來到Alamofire.swift
看到這個request
方法: app
Url
參數,這個方法返回一個
DataRequest
對象,是利用
SessionManager
的
request
方法,這說明了真正的
request
應該是由
SessionManager
發起的,下面再來看一下
SessionManager.default.request
方法內部實現了什麼❓
在這個方法中建立了一個
URLRequest
對象,並把傳入的參數傳入到這個
URLRequest
對象中,並調用了
request
方法,而且把上面建立的
URLRequest
對象進行編碼以後做爲參數傳入到這個
request
方法,
這裏是插入一個小插曲,這個參數編碼究竟是如何操做的,也就是這個encoding.encode()
方法具體實現了什麼?框架
encode()
這個方法傳入了參數
parameters
,而在這裏處理這個
parameters
的是
query(parameters)
,那麼接着來看這個
query
方法的具體實現:
來到這裏把傳入的參數根據key
進行排序,而後遍歷排序的結果,而後利用queryComponents
方法將全部的參數(key,value)
不斷的遞歸, 返回一個元素爲元組的數組,而後將這個數組進行map
映射,將key=value
而且拼接&
符號,至此就完成了參數的拼接,異步
📣而後咱們在回到encode
方法中,根據請求方法的不一樣,post
.get
, .head
, .delete
類型,須要urlComponents.percentEncodedQuery
進行百分號編碼,而且利用query(parameters)
把參數直接拼接到URL
後面。.post
,須要設置請求頭application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type
,而後利用query(parameters)
拼接參數,將參數轉換爲二進制並賦值到urlRequest.httpBody
請求體中。那麼接下來回到request
的流程再來看看這個request(encodedURLRequest)
方法內部實現了什麼❓
在這裏先拿到傳入的已經編碼事後的URLRequest
,這裏的DataRequest
是繼承於Request
的一個子類,用來管理URLSessionDataTask
,而這裏DataRequest.Requestable
,難道是調用了一個Requestable
方法?咱們跟進去這個Requestable
看一下:
能夠看到這個Requestable
是一個結構體,也就是說在當前這個DataRequest
類裏面嵌套了一個結構體,可是能夠看到這個結構體內部並無urlRequest
這個方法,那它怎麼會調用urlRequest
方法呢?
咱們來看這句代碼let urlRequest: URLRequest
,能夠看到在這個結構體的內部有個urlRequest
屬性,並且默認初始化。✍️那麼這句DataRequest.Requestable(urlRequest: )
實際上就是建立了一個類型爲Requestable
的並且包含建立task
方法的結構體對象,在這個task
方法的內部返回的是同步建立的session
,return queue.sync { session.dataTask(with: urlRequest) }
.
🗣🗣🗣那麼這裏爲何不使用DataRequest
直接建立一個task
,而非要task
由Requestable
這個結構體來建立,實際上是Requestable
結構體就至關因而DataRequest
的祕書,其實這裏DataRequest
和task
任務應該是一一對應的,平級關係,若是DataRequest
直接建立task
,更像是歸屬關係,而由Requestable
來建立task
也就是下降了DataRequest
與task
的耦合性,使DataRequest
與task
保持平級關係。
Requestable
建立完
task
以後,緊接着
DataRequest
就建立了一個
request
,那麼接下來來到
DataRequest
的
init
方法,然而
DataRequest
並無
init
方法,那麼就看其父類
Request
的
init
方法:
能夠看到這裏
requestTask
很明顯是個枚舉類型,
而這個
requestTask
調用了一個關聯方法
.data(let originalTask, let task)
,而這個
.data
便是
DataRequest
初始化方法中傳入的
.data(originalTask, task)
,這裏會根據傳入的方法的不一樣的類型來把
task
交給不一樣的
TaskDelegate
.
再一次回到request
流程的源碼🤷♂️🤷♂️🤷♂️ ,這裏一句很重要的代碼 delegate[task] = request
,這裏是作了一個綁定操做,(有點相似於字典和數組),當前這個delegate
由源碼可知public let delegate: SessionDelegate
是一個SessionDelegate
就是SessionDelegate
經過task
能夠讀取到request
。方便在 SessionDelegate
下發任務的時候,經過task
直接檢索,方便直接獲取到request
,而後調用request.resume()
任務啓動.
SessionDelegate
實現代理, 爲何這裏還要有一個DataTaskDelegate
, 真是費勁呢。
首先,要明白要SessionDelegate
是全部 Session
的代理遵循者,任何的代理都會來到這裏響應,而DataTaskDelegate
是具體任務的實現者,這裏面全部方法都是由 SessionDelegate
下發響應的。(一個下發任務,一個具體幹活)
下面給我一首歌的時間🎤🎤🎤來看一下SessionDelegate.swift
中URLSessionDownloadDelegate
的源碼🌰:
self[downloadTask]
就等同於
DownloadRequest
,
DownloadRequest.delegate
就等同於
DownloadTaskDelegate
.這裏把
downloadTask
交給了
DownloadTaskDelegate.urlSession
去執行,若是再跟進去源碼
DownloadTaskDelegate.urlSession
,就會發現執行的就是具體的
Download
操做。
在SessionManager
的 Request
方法中,表面上看是由SessionManager
直接處理了request
,然而實際上,是經過SessionManager
的代理響應SessionDelegate
,而後SessionDelegate
把這個具體Request
分發給了具體的DataTaskDelegate
,而後DataTaskDelegate
來執行具體的任務內容。之因此這麼作,是由於SessionDelegate
經過的任務分發,讓處理具體任務的taskdelegate
去處理對應的事務,避免了其內部邏輯混亂和代碼冗餘,實現任務邏輯下沉。關於Request
還有不少內容的哦,後面再作補充,若有錯誤,還望大佬們指正。