Alamofire 原始碼剖析

發表於2016-12-27

Alamofire 是什麼?

  • 在功能角度,Alamofire是一個http請求框架。使用它可以很方便的處理http請求(請求資料,下載,上傳)。
  • 在程式碼實現角度,Alamofire是對NSURLSession的封裝。
  • 在語言角度可以理解為AlamofireAFNetworking的Swift實現(它們出自同一作者)。

本博文適用物件

在這篇博文我 不會闡述Alamofire的使用方法而是介紹Alamofire的設計思想和組織結構 。希望這篇博文能夠拋磚引玉,助你輕鬆的理解Alamofire的實現細節。

NSURLSession概述

Alamofire是對NSURLSession的封裝, 在分析Alamofire前,我們先簡單看下NSURLSession的api。

Creating a Session

Configuring a Session

Adding Tasks

  1. Adding Data Tasks to a Session
  2. Adding Download Tasks to a Session
  3. Adding Upload Tasks to a Session
  4. Adding Stream Tasks to a Session

    框架核心:Manager

    Alamofire.swift檔案中定義了一組方法以方便我們進行 request, download,upload操作(差不多解決了90%的需求吧)。 這些方法只是為了方便使用,真正做事情的是類ManagerManager才是框架的核心。框架結構如下:

111748276-40ca408f27e20737
Manager.png
  • session: 所有的task都是由這個session建立的,也就是說對session 的配置資訊作用於所有的task。
  • delegate: session的代理由專門的類SessionDelegate負責。SessionDelegate實現了 NSURLSessionDelegate, NSURLSessionTaskDelegate,NSURLSessionDataDelegate,
    NSURLSessionDownloadDelegate 協議,並實現了這些協議的所有方法。SessionDelegate就是回撥事件的樞紐中心,完成回撥的統一處理和散發。
  • backgroundCompletionHandler:當需要執行後臺操作任務時使用。具體內容:NSURLSession使用說明及後臺工作流程分析
  • AddingTasksMethod:這是一組建立Task的方法。上面 NSURLSession概述 中提到一組 Adding Tasks 方法, 框架對這些方法進行了封裝,我們統一稱這組方法為AddingTasksMethod。 在後面的 建立Task 部分再細說。
  • startRequestsImmediately:當建立task後,需要呼叫這個task的resume方法才會開始執行。startRequestsImmediately=true時, 建立好task就會resume。

看下初始化方法:

至此我們已經建立好了session和它的delegate。呼叫流程大致這個樣子: 通過Manager建立sessionSessionDelegate物件——>使用AddingTasksMethod建立task—–>task呼叫resume()開始執行——>呼叫SessionDelegate中實現的代理方法。

使用閉包過載代理方法

為了使用框架的靈活性,SessionDelegate為每一個delegate方法宣告瞭一個對應的閉包。這樣你就可以很方便的指定如何處理回撥。

121748276-fa59b2f339b09542
代理方法對應的閉包.png

例如:

建立Task

框架中對 NSURLSession概述 中的 Adding Tasks 方法進行了封裝,組成了前面提到的AddingTasksMethod。

131748276-541e9486d5a18f59
addTaskMethod

request

通過呼叫下面的方法,建立NSURLSessionDataTask物件。

在上面程式碼中,URLRequest.URLRequest 就是一個NSMutableURLRequest 物件。我們使用NSMutableURLRequest建立了一個NSURLSessionDataTaskqueue 是序列佇列,在序列佇列 queue中執行同步方法能夠確保建立task時的執行緒安全。對執行緒有疑惑的可以看這裡GCD 深入理解:第一部分

download

通過呼叫下面的方法,建立URLSessionDownloadTask物件。 下載包括兩種方式:直接下載和斷點續傳。download方法通過enum對不同型別進行區分。destination 引數是一個閉包,用於在下載結束後確定將下載的檔案儲存在什麼路徑。

upload

通過呼叫下面的方法,建立URLSessionUploadTask物件。 upload分為三種:上傳NSData,上傳NSURL指定的檔案,還有NSInputStream。在upload方法中使用列舉來區分不同的上傳內容。 邏輯很簡單,不在贅述。

stream

通過下面的方法生成NSURLSessionStreamTask物件。

重構,各司其職

存在的問題

到此總算把各種Task建立出來了。呼叫Task的resume方法就可以開始執行任務。從伺服器返回資料後就會呼叫SessionDelegate的代理方法。當同時執行多個Task時,我的天,發生了什麼。。。 下面就拿NSURLSessionDataTask舉例。當多個task同時執行時,他們會交替頻繁的呼叫SessionDelegate代理方法。

141748276-331e66f2fb285b85
Snip20161215_8.png

現在我有下面幾個需求:

  • 顯示出每個task的執行進度
  • task1得到全部資料後解析成jsonObject, task2得到全部資料後解析成string, task3得到全部資料後解析成propertyList。。。。

建立TaskDelegate及子類,為每個task建立專有的delegate物件

要滿足上面的需求,我們必須為每一個task建立一個代理物件,這個代理物件只處理這個task的代理回撥。TaskDelegate及子類就是用於做這件事情的。

151748276-5eaf6fe773f8de41
Snip20161215_5.png

執行步驟是這個樣子的:

  1. 我們建立了一個建立NSURLSessionDataTask物件dataTask1;
  2. 建立dataTask1對應的DataTaskDelegate物件dataTask1Delegate;
  3. dataTask1獲取到資料後呼叫SessionDelegatepublic func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)
  4. SessionDelegatepublic func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)方法中呼叫DataTaskDelegatepublic func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didReceiveData data: NSData)方法。

使用Request封裝建立TaskDelegate的過程

為了方便建立TaskDelegate 物件,框架有一個Request類。Request所做的事情就是為每個Task生成對應的TaskDelegate物件。

修改建立Task方法

現在我們需要修改建立Task的方法如下(以request為例):

設定好了之後, 在回撥中根據task取出這個task對應的代理物件, 然後執行對應的方法就ok了。

處理響應結果

TaskDelegate類中有序列佇列queue:NSOperationQueue,並設定這個佇列的queue.suspended = true(新增block不會執行,直到suspended=false) 你可以這個佇列中新增要執行的block。在func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?) 代理方法中如果error=nil,設定queue.suspended = false。 處理相應結果大致就是這個原理。

寫在最後

  • 為了便於理解,在學習框架時畫的腦圖,相對於文字,腦圖結構更加清晰明瞭。Alamofire框架腦圖
  • 雖然寫了這麼多但還是感覺很多點沒有提到。比如說用於對請求引數編碼的ParameterEncoding,用於對請求響應資料序列化的ResponseSerialization,用於https驗證伺服器證書的ServerTrustPolicy, upload操作中對MultipartFormData的具體實現。這些程式碼質量都很高,值得推薦。
  • 能力有限,難免出現錯誤。如發現問題希望不吝指教。
  • 寫這麼多著實佔用不少時間,如果對你有幫助,那就給個喜歡吧。

相關文章