天天看點

iOS開發之Alamofire源碼深度解析

我們先整體上來看一下AlamoFire這個架構關系,概述一些核心子產品。該部分我們先來看一下AlamoFire的檔案組織結構,然後在給出這些檔案組織結構中類的關系。是以在本部分類圖是少不了的。廢話少說,進入該部分的主題。

首先我們來看一下AlamoFire的目錄結構,從整體上來把控一下AlamoFire。下方截圖是AlamoFire架構的所有檔案,檔案不算多,Alamofire架構的源代碼并不算多,所有理清Alamofire的架構結構還是不難的。下方截圖中是AlamoFire中的所有檔案,Core檔案夾下是Alamofire的核心檔案,Features主要是對核心檔案的擴充。今天我們就以核心檔案為主,Feature檔案為輔來窺探一下AlamoFire架構的源碼。

下方是對Core檔案夾下的各個檔案的功能簡述:

Alamofire.swift ---- 該檔案中主要是給使用者提供一些便利的調用方法,使用者可以直接調用該檔案中的便利方法來使用Alamofire相關功能。
Manager.swift ---- Manager中定義了Session對象,Session相關的Delegate,以及Delegate執行的隊列等相關資訊,在Manager中建立Request對象發起請求。Manager管理的就是各種請求,Manager對象是以單例的形式對外開放的。
Request.swift ---- 該檔案如其名,就是負責建立Session的各種task的,并執行相關的SessionTask,并調用相關書籍解析的功能子產品對資料進行解析并通過回調傳回給使用者。
ParameterEncoding.swift ---- 負責請求參數的各種編碼(URL、URLEncodedInURL、JSON、PropertyList等編碼),并将編碼後的資料與URLRequest結合後的結果進行傳回。
Result.swift ---- 對解析後的資料封裝成Result對象。
Response.swift ---- 負責将伺服器相應的資料進行封裝生成Response對象,該對象中就包括上述的Result對象,使用者最終會通過閉包回調的形式擷取到該Response的對象。
Notifications.swift ---- 其中是一個Notification結構體,該結構體中定義了一些字元串,這些字元串就是所需通知的Key,當網絡請求DidResume、DidSuspend、DidCancel、DidComplete都會發出通知。
Error.swift ---- 其中是一個Error的結構體,其中封裝的是各種錯誤狀态。

Features檔案夾下各個檔案的功能簡述:

Download.swift ----- 對Manager和Request類進行擴充,使其支援Down Task,其中封裝了NSURLSessionDownloadDelegate相關代理方法。
Upload.swift ---- 在該檔案中也是對Manager和Request類進行的擴充,使其支援Upload Task,其中封裝了NSURLSessionDataDelegate中擷取上傳資料進度的代理方法,也就是taskDidSendBodyData代理方法。
MultipartFormData.swift ---- 該檔案從名字就可以看出是為了組織多表單資料上傳的資料的,在Upload Task中就使用到了MultipartFormData。
Stream.swift ---- 和Download和Upload檔案相似,該檔案中也是對Manager和Rquest做延展,主要使其支援資料流的傳輸,其中主要封裝和實作了NSURLSessionStreamDelegate相關的代理方法。
ResponseSerialization.swift ---- 該檔案中主要是對Request類進行資料解析的延展的。其中封裝了各種對響應資料的解析方式,其中包括Data、String、JSON、PropertyList等解析方式。
NetworkReachabilityManager.swift ---- 該檔案主要是對SystemConfiguration.framework中的SCNetworkReachability相關的東西進行封裝的,主要用來管理和監聽網絡狀态的變化。
ServerTrustPolicy.swift ---- 這個檔案主要是對NSURLSession做的延展,其中定義了各種網絡請求的認證政策,主要證書認證相關東西。
Timeline.swift ---- 該檔案是為了友善調試而生的,其中記錄了相關操作的時間點,并且對其進行記錄,便于在Debug時使用到。
Validation.swift ---- 主要是用來驗證請求是否成功,如果出錯了就做相應的處理。

上面是AlamoFire中所有檔案的概述,上面這些算是對AlamoFire架構有大概的了解吧。結合上方的概述,來研讀AlamoFire源碼還是比較清晰的。下方就是AlamoFire 3.4中相關檔案的木頭結構,如下所示:

  

iOS開發之Alamofire源碼深度解析

上面簡單的介紹了Alamofire架構的目錄結構以及每個檔案所負責的内容。接下來我們進入到各個檔案的内部,來整體的看一下核心類之間的關系。下方是核心類的“類圖”,當然下方隻是核心類的。接下來來概述一下下方的類圖,因為下圖太大,在此看起來不太清楚,如果你感興趣,你可以另存為,然後放大檢視。

下方黑框中的部分對應的就是Alamofire.swift中的内容。其中主要是一些URL轉換字元串的延展以及URLRequst轉換成MutableURLRequest的延展,還有一些使用者使用的便利方法。
黃框中就是我們Manager.swift中的内容了,Manager類的對象是以單例的形式對外展現的,上述黑框中的便利方法,主要是擷取Manager類的單例,然後調用相應的方法。
綠框中所對應的主要是Request.Swift和Features檔案夾中的内容,主要是Request類及其延展,當然還有對Manager和NSURLSession的延展。
紅框中的就是網絡請求會話的各種任務的回調方法的封裝了,在這些回調方法中提供了預設實作,并對外留有回調塊,以便讓使用者來自己實作這些回調方法。
iOS開發之Alamofire源碼深度解析

第一部分算是概覽了一下Alamofire架構中的各個組成部分,接下來該進入到上述的各個子產品中來進一步來窺探其實作群組織方式了。還是“順藤摸瓜”,先從使用者看的到的地方着手,然後層層深入,直到你看不見的地方。是以第二部分我們先來看一下Alamofire.swift中的内容,因為該檔案是Alamofire架構的入口。

下方的類圖就是第一部分類圖中黑框的放大版,根據Alamofire.swift這個檔案我們不難畫出下方這個類圖。有一點要說明的就是在類圖中省略了一些周遊方法,隻寫了一些主要的,不過核心的功能還是有的。下方的URLStringConvertible和URLRequestConvertible是負責類型轉換的接口,具體的請看下方的介紹。該檔案中除了類型轉換的方法外就是一些調用Manager的單例的便利方法了。

iOS開發之Alamofire源碼深度解析

下方就是URLStringConvertible協定以及相關延展的具體實作,主要功能就是将String、NSURL、NSURLComponents、NSURLRequest中的URL轉換成字元串類型。将要轉換的類型要遵循URLStringConvertible協定,并在計算變量URLString中傳回轉換後的字元串。具體做法如下所示,這中類型轉換方式在開發中經常會使用到,下方會給出其他執行個體。URLRequestConvertible協定的功能與URLStringConvertible大同小異,URLRequestConvertible協定的實作者負責将NSURLRequest轉換成NSMutableURLRequest類型。在此就不做過多的贅述了。

iOS開發之Alamofire源碼深度解析

下方截圖是Alamofire.swift中的一個便利方法,其他幾個便利方法與此相似,都是調用Manager單例中相應的方法,便利方法為了鍊式調用Request類中的相關方法,是以所有的便利方法都會傳回目前Manager單例使用的Request對象。具體如下所示:

iOS開發之Alamofire源碼深度解析

學以緻用,舉一反三。上面那種“面向協定”開發的思想值得我們學習,之前在設計模式相關的系列部落格中不止一次的提到過要“面向接口程式設計”,此處的協定就是接口。雖然上面隻是使用協定來進行簡單的類型轉換,這種思想是非常值得我們學習的。通過上面類型轉換的方式,我們可以寫出下方代碼。下方代碼不是Alamofire架構中的代碼,是我根據上述的類型轉換的執行個體所實作的,下方定義了一個類型轉換的協定,需要轉換的類型要遵循這個協定,下方以String為例,具體做法如下所示。

iOS開發之Alamofire源碼深度解析

因為便利方法主要是調用的Manager類的單例,是以接下來我們來看Manager.swift中的東西。Manager類中主要負責Session和Request的初始化,并且提供SessionDelegate代理方法的預設實作。在實作代理方法時留出了相應的閉包已提供給使用者使用該閉包來回調相應的代理方法。在Manager中的SessionDelegate類就是NSURLSessionDelegate以及相關子協定的代理類 ,其中就給出了各個代理方法的預設實作,在實作時并定義了一系列的Closure回調變量,當這些閉包變量不為空時就會執行閉包塊中的内容,而不會執行提供的預設實作。

下方類圖就是黃色部分的放大版,主要是Manager類與SessionDelegate的關系。從下方類圖中不難看出,SessionDelegate類遵循了NSURLSessionDelegate協定以及子協定,并給出了代理相應的實作方法。下方的代碼會給出代理的具體封裝和實作方式。

iOS開發之Alamofire源碼深度解析

開門見山,因為Manager類對外是以單例的形式對外使用的,是以我們先來看看Manager類的單例實作。下方截圖中的sharedInstance計算屬性就是Manager的單例,其中存儲的就是一個Manager對象,在建立Manager對象時我們為Manager對象中存儲的NSURLSession對象指定了一個defaultSessionConfiguration和一個defaultHTTPHeaders。

iOS開發之Alamofire源碼深度解析

上面是Manager類中單例的實作,接下來我們來解析類中核心的屬性,下方是一些核心屬性的解析:

defaultHTTPHeaders屬性 : defaultHTTPHeaders是Manager類中的一個計算屬性,負責組織預設的請求Header中的内容。
session屬性: 該屬性的類型是NSURLSession類型的,負責請求會話,并建立各種會話任務。
queue屬性:該屬性是一個串行隊列,該隊列負責執行session建立Session Task的任務。
delegate屬性:該屬性是SessionDelegate類型的,而SessionDelegate類遵循了NSURLSessionDelegate及其子協定,并給出了相應的實作,在下方會着重介紹SessionDelegate。而此處的delegate屬性負責調用SessionDelegate類中相應的回調方法。

在Manager.swift源檔案中給出了request方法的實作,Manager類的單例所調用的upload、download等方法是在其他源檔案中做的延展。那些延展中的方法稍後在聊,本部分中就先對request方法進行解析。下方的方法就是我們在便利方法中使用Manager類的單例所調用的方法。method參數表示請求方式(GET, POST, PUT等),URLString參數是請求位址,parameter就是請求參數了。encoding參數就是請求參數的編碼方式,此處預設是URL編碼。headers字典參數就是請求頭資訊了,預設為nil。下方代碼主要是建立NSMutableURLRequest對象,然後将參數進行相應的編碼後添加進NSMutableURLRequest對象中,然後調用request()方法發起請求。

iOS開發之Alamofire源碼深度解析

下方代碼段是上述函數中所調用的request()方法,下方的request()方法負責通過Session建立dataTask,也就是負責執行Data Task任務。然後在初始化Request類的對象時,将建立的Data Task對象傳給Request對象。然後将Request對象的 Task Delegate對象存入Manager類的delegate屬性中。因為在delegate屬性中的代理方法是調用相應的Task Delegate的方法,是以在此有必要進行存儲。然後調用Request對象的resume()方法發起資料的網絡請求。為了鍊式調用Request對象的其他方法,是以将Request類的對象進行傳回。代碼如下所示:

iOS開發之Alamofire源碼深度解析

SessionDelegate可以說是代理的代理,因為在SessionDelegate中有一個subdelegates字典屬性,該屬性負責存儲Request對象中的各個Task Delegate。而SessionDelegate在相應的代理方法中會通過存儲的Task Delegate來調用Task Delegate中的方法,是以SessionDelegate說是代理的代理。

下方代碼段是SessionDelegate類中部分代碼的截圖,其中的subdelegates字典屬性中存儲的就是Request中的TaskDelegate,subdelegateQueue是一個并行隊列用來同步執行擷取和設定字典中的Task Delegate對象。然後就是為SessionDelegate類定義了一個下标,該下标的功能是以Session Task為下标的形式向subdelegates中添加和擷取相應的Task Delegate。該自定義下标就可以讓類的對象使用下标的形式來設定和擷取屬性的值,稍後會給出擴充的Demo。

iOS開發之Alamofire源碼深度解析

關于SessionDelegate中所實作的代理方法,在此我們就一執行Data Task請求的didReceiveData代理方法為例。下方截圖就是SessionDelegate中的didReceiveData代理方法。代碼比較簡單,首先判斷該代理方法對象的Closure回調變量是否有值,如果有就執行該閉包回調塊,如果沒有值就擷取我們存儲的Data Task Delegate, 然後去執行Data Task Delegate中的didReciveData方法。其他方法也于此類似,是以就以點代面,在此就不做過多的贅述了。

iOS開發之Alamofire源碼深度解析

接下來有到了舉一反三,擴充知識點的時刻了。接下來我們單獨來建立一個小執行個體來看一下Swift中自定義下标是怎麼回事。大道至簡,接下來我們将上述下标的使用進行簡化,建立一個Demo, 然後通過這個Demo來介紹一下下标的使用。

下方代碼段就是我們建立的簡化版的下标示例,在Swift的類中是支援自定義下标的,自定下标可以讓你以下标的形式來通路和設定屬性。下方就自定義了一個下标,在下标中設定和傳回value屬性的值。用法如下所示:

iOS開發之Alamofire源碼深度解析

逐漸深入,我們現在來到了Request.swift這個類,因為上面的Manager中的請求最終走到了Request類的位置,是以接下來我們要分析的就是Request.swift源檔案中的内容。Request.swift源檔案中主要是執行的Data Task請求,并且實作了相應的Data Task Delegate中的方法。其他的任務例如Download Task, Upload Task,Stream Task等會在其他檔案中對Request做延展時執行上述這些任務。我們在此就以Data Task為例。Request類中說白了就是負責通過會話建立相應的Task,并實作相應Task的代理方法。

下方類圖就是Request相關類圖了,Request類及其延展中就是建立各種類型的Task,然後給出相應的Task Delegate。下方類圖還給出個各種Task Delegate間的繼承關系。Request相關源檔案在給出TaskDelegate的代理方法的實作時,也封裝了閉包狀态下的回調方法。這中做法與SessionDelegate中做法一緻。下方會給出具體的介紹。

iOS開發之Alamofire源碼深度解析

下方就是Request類的初始化方法,方法需要兩個參數,第一個參數是NSURLSession的對象,該對象也就是Manager單例中建立的Session的對象。而第二個參數雖然是Manager傳過來的,但是初始化task的任務還得交給Request類來做,Manager來隻不過是定義了一個NSURLSessionTask的類型傳到了Request中,例如在Manager的request()方法中task是NSURLSessionDataTask,Manager的upload()方法中的task是NSURLSessionUploadTask類型。

在Request的初始化方法中根據Manager單例提供的task的類型來确定是建立DataTaskDelegate、UploadTaskDelegate等。在相應的Task Delegate中會建立相應的Task。我們還以上述的DataTask為例,如果你調用Manager單例中的request()方法就會執行下方的DataTaskDelegate()的初始化。如下所示:

iOS開發之Alamofire源碼深度解析

上面的delegate是TaskDelegate類型的,因為UploadTaskDelegate、DownloadTaskDelegate以及DataTaskDelegate都是TaskDelegate的子類,是以此處用到了面向對象的“多态性”。下方兩個屬性就是Request類中的delegate和task屬性,delegate的初始化在上述Requset的初始化方法中,而此處的task是一個存儲屬性,task的初始化是放在相應的TaskDelegate中的,在TaskDelegate中建立完task對象後再指派給Request類中的task屬性,如下所示:

iOS開發之Alamofire源碼深度解析

在使用Request類的對象時,我們可以鍊式的調用Request中的方法,最常用的就是擷取相應任務執行的進度,也就是平時我使用的progress()方法。下方截圖中的代碼段就是progress()方法的實作。通過Task Delegate的類型來判斷目前執行的哪種任務,然後将傳過來的progress的閉包指派給相應的Task Delegate,在這些Task的Delegate中會在相應的回調方法中擷取任務執行進度,然後執行下方傳入的Closure。

iOS開發之Alamofire源碼深度解析

下方就是Request類中的resume()方法,其中的代碼比較簡單。主要是用來記錄startTime,然後調用task的resume方法開始執行任務。當然在開始執行任務後要發起相應的通知,此處發出的是DidResume通知。所有的通知類型都在Notifications.swift檔案中的Notifications結構體中存儲着。Request類中的其他方法,比如suspend()、cancel()方法的實作方式與resume()類似,并且都會發出相應的通知,在此就不做過多的贅述了。

iOS開發之Alamofire源碼深度解析

從第一部分中的類圖中我們能看出與Request類相關的代理類,TaskDelegate是所有代理類的基類。在該代理類中其實就是定義了一下必要的屬性和NSURLSessionTaskDelegate中對應的回調方法,并且為這些回調方法提供相應的閉包回調的形式。此處就以TaskDelegate代理類為例。下方就是TaskDelegate代理類為NSURLSessionTaskDelegate中相應的代理方法提供的Closure方式。其他的代理類如DataTaskDelegate、DownloadTaskDelegate等與此類似。而相應的代理方法中就是對回調進行了處理,不過在處理之前會判斷相應的Closure是否為nil, 如果不為nil的話就執行Closure閉包塊中的内容。如果為nil,就執行提供的預設處理。

iOS開發之Alamofire源碼深度解析

事無巨細,至此Alamofire中的核心類就已經介紹完畢,因為篇幅有限,其他類在此就不做過多贅述了。其他類以及其他檔案中的内容在第一部分中做了概述,其内部的實作細節就不做過多贅述了,在Github上分享的代碼對這些類的關鍵技術細節給出了注釋。

在Alamofire架構中大量的使用了延展、閉包以及枚舉關聯值。特别是在解析網絡請求的資料時,将閉包類型作為函數的參數,然後通過閉包變量來提供相應的解析方案,在此就不做過多的贅述了,其他技術細節“仁者見仁,智者見智”。聽我說再多,看再多的技術部落格如果不親自的去了解一下,說再多也是沒用的,實踐出真知。

      本文轉自zsdnr  51CTO部落格,原文連結:http://blog.51cto.com/12942149/1929665,如需轉載請自行聯系原作者