Alamofire學(xué)習(xí) -- Request

前言

通過上一篇URlSession后臺下載,我們已經(jīng)知道了SessionManager的作為整個Alamofire框架的核心樞紐的重要性??,還有一個比較重要的是SessionManager的代理SessionDelegate,封裝了URLSessionDelegate。負責對Task的回調(diào)事件提供默認實現(xiàn)(轉(zhuǎn)發(fā)給TaskDelegate進行實際處理),并且以閉包的方式暴露給外部,讓外部可以自定義實現(xiàn)。TaskDelegateURLSessionTask的回調(diào)進行實際的處理,并且執(zhí)行task的完成回調(diào)用。Request就 是對URLSessionTask的封裝,是暴露給上層的請求任務(wù)。

Alamofire Request

廢話不多說直接來用URLSession創(chuàng)建一個request和利用Alamofire創(chuàng)建一個request的例子??看看:

首先來看一個URLSessionrequest的用法:

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()  

再來看一個基礎(chǔ)的Alamofire.request用法:

Alamofire.request("https://www.douban.com/j/app/radio/channels").responseJSON { (response) in  
    if let JSONString = response.result.value {  
        print("JSONString: \(JSONString)")  
    }  
}  

有沒有覺得,如果使用系統(tǒng)的API,我們不得不先創(chuàng)建URL,然后建立dataTask,并且resume,接著在callback里去解析JSON。由于Swift是一種強類型的語言,我們不得不進行大量的邏輯判斷和try-catch???♂?。而Alamofire把這些步驟簡化成了一個靜態(tài)的方法調(diào)用,并且用鏈式的方式來處理異步的Response解析。由于是鏈式的,我們也可以用鏈式的方式實現(xiàn)更多的邏輯。

那么在Alamofire.request的內(nèi)部具體做了什么“騷”操作呢???沒辦法???♀??,想要看到內(nèi)部實現(xiàn),就要看到這里的源碼,那么就來吧...

根據(jù)Alamofire.request的這個方法,我們來到Alamofire.swift看到這個request方法:


可以看到這個方法里的幾個參數(shù)都有默認值,所有我們可以直接傳入一個Url參數(shù),這個方法返回一個DataRequest對象,是利用SessionManagerrequest方法,這說明了真正的request應(yīng)該是由SessionManager發(fā)起的,下面再來看一下SessionManager.default.request方法內(nèi)部實現(xiàn)了什么?


在這個方法中創(chuàng)建了一個URLRequest對象,并把傳入的參數(shù)傳入到這個URLRequest對象中,并調(diào)用了request方法,并且把上面創(chuàng)建的URLRequest對象進行編碼之后作為參數(shù)傳入到這個request方法,

這里是插入一個小插曲,這個參數(shù)編碼到底是如何操作的,也就是這個encoding.encode()方法具體實現(xiàn)了什么?


這里先取出請求方法的類型,然后根據(jù)不同的類型對參數(shù)進行不同的編碼,由前面的代碼我們知道在encode()這個方法傳入了參數(shù)parameters,而在這里處理這個parameters的是query(parameters),那么接著來看這個query方法的具體實現(xiàn):

來到這里把傳入的參數(shù)根據(jù)key進行排序,然后遍歷排序的結(jié)果,然后利用queryComponents方法將所有的參數(shù)(key,value)不斷的遞歸, 返回一個元素為元組的數(shù)組,然后將這個數(shù)組進行map映射,將key=value并且拼接&符號,至此就完成了參數(shù)的拼接,

??然后我們在回到encode方法中,根據(jù)請求方法的不同,

  • 如果請求方法是.get, .head, .delete類型,需要urlComponents.percentEncodedQuery進行百分號編碼,并且利用query(parameters)把參數(shù)直接拼接到URL后面。
  • 如果是其他類型的請求方法,例如.post,需要設(shè)置請求頭application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type,然后利用query(parameters)拼接參數(shù),將參數(shù)轉(zhuǎn)換為二進制并賦值到urlRequest.httpBody請求體中。

那么接下來回到request的流程再來看看這個request(encodedURLRequest)方法內(nèi)部實現(xiàn)了什么?

在這里先拿到傳入的已經(jīng)編碼過后的URLRequest,這里的DataRequest是繼承于Request的一個子類,用來管理URLSessionDataTask,而這里DataRequest.Requestable,難道是調(diào)用了一個Requestable方法?我們跟進去這個Requestable看一下:

可以看到這個Requestable是一個結(jié)構(gòu)體,也就是說在當前這個DataRequest類里面嵌套了一個結(jié)構(gòu)體,但是可以看到這個結(jié)構(gòu)體內(nèi)部并沒有urlRequest這個方法,那它怎么會調(diào)用urlRequest方法呢?

我們來看這句代碼let urlRequest: URLRequest,可以看到在這個結(jié)構(gòu)體的內(nèi)部有個urlRequest屬性,而且默認初始化。??那么這句DataRequest.Requestable(urlRequest: )實際上就是創(chuàng)建了一個類型為Requestable的而且包含創(chuàng)建task方法的結(jié)構(gòu)體對象,在這個task方法的內(nèi)部返回的是同步創(chuàng)建的sessionreturn queue.sync { session.dataTask(with: urlRequest) }.

??????那么這里為什么不使用DataRequest直接創(chuàng)建一個task,而非要taskRequestable這個結(jié)構(gòu)體來創(chuàng)建,其實是Requestable結(jié)構(gòu)體就相當于是DataRequest的秘書,其實這里DataRequesttask任務(wù)應(yīng)該是一一對應(yīng)的,平級關(guān)系,如果DataRequest直接創(chuàng)建task,更像是歸屬關(guān)系,而由Requestable來創(chuàng)建task也就是降低了DataRequesttask的耦合性,使DataRequesttask保持平級關(guān)系。


繼續(xù)回到源代碼,可以看到在Requestable創(chuàng)建完task之后,緊接著DataRequest就創(chuàng)建了一個request,那么接下來來到DataRequestinit方法,然而DataRequest并沒有init方法,那么就看其父類Requestinit方法:


可以看到這里requestTask很明顯是個枚舉類型,


而這個requestTask調(diào)用了一個關(guān)聯(lián)方法.data(let originalTask, let task),而這個.data 即是DataRequest初始化方法中傳入的.data(originalTask, task),這里會根據(jù)傳入的方法的不同的類型來把task交給不同的TaskDelegate.

再一次回到request流程的源碼???♂????♂????♂? ,這里一句很重要的代碼 delegate[task] = request,這里是做了一個綁定操作,(有點類似于字典和數(shù)組),當前這個delegate由源碼可知public let delegate: SessionDelegate是一個SessionDelegate就是SessionDelegate通過task可以讀取到request。方便在 SessionDelegate 下發(fā)任務(wù)的時候,通過task直接檢索,方便直接獲取到request ,然后調(diào)用request.resume()任務(wù)啟動.


直接通過SessionDelegate實現(xiàn)代理, 為什么這里還要有一個DataTaskDelegate, 真是費勁呢。

首先,要明白要SessionDelegate是所有 Session 的代理遵循者,任何的代理都會來到這里響應(yīng),而DataTaskDelegate 是具體任務(wù)的實現(xiàn)者,這里面所有方法都是由 SessionDelegate 下發(fā)響應(yīng)的。(一個下發(fā)任務(wù),一個具體干活)

下面給我一首歌的時間??????來看一下SessionDelegate.swiftURLSessionDownloadDelegate的源碼??:


從標紅部分可以看出,self[downloadTask]就等同于DownloadRequestDownloadRequest.delegate 就等同于DownloadTaskDelegate.這里把downloadTask交給了DownloadTaskDelegate.urlSession去執(zhí)行,如果再跟進去源碼DownloadTaskDelegate.urlSession,就會發(fā)現(xiàn)執(zhí)行的就是具體的Download操作。

總結(jié)

SessionManagerRequest 方法中,表面上看是由SessionManager直接處理了request,然而實際上,是通過SessionManager的代理響應(yīng)SessionDelegate,然后SessionDelegate把這個具體Request分發(fā)給了具體的DataTaskDelegate,然后DataTaskDelegate來執(zhí)行具體的任務(wù)內(nèi)容。之所以這么做,是因為SessionDelegate 通過的任務(wù)分發(fā),讓處理具體任務(wù)的taskdelegate 去處理對應(yīng)的事務(wù),避免了其內(nèi)部邏輯混亂和代碼冗余,實現(xiàn)任務(wù)邏輯下沉。關(guān)于Request還有很多內(nèi)容的哦,后面再做補充,如有錯誤,還望大佬們指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容