當前位置:
首頁 > 最新 > 用Swift編寫網路層:面向協議方式

用Swift編寫網路層:面向協議方式

在這篇文章中我們會看到怎樣實現用純swift編寫網路層,而不依靠任何第三方庫。讓我們快去看看吧。相信看完之後我們的代碼能夠做到:

面向協議

易用

容易實現

類型安全

用枚舉(enums)來配置終端(endPoints)

下面是一個最終我們網路層的示例

這個項目的最終目標

通過輸入router.request(. 藉助枚舉的力量,我們可以看到所有有效的終端和我們請求的參數)

首先,一些結構

創建任何東西之前,有個結構都是很重要的,這樣後面我們就容易找到需要的東西。我堅定相信文件夾結構對軟體架構至關重要。為了讓我們的文件組織有序,讓我們提前建立好所有的組,我會標記好每一個文件該放的位置。這是一個項目結構總覽。(請注意這裡的名字僅僅是建議,你可以按你喜好給你的類和組命名)

項目文件夾結構

終端類型(EndPointType)協議

我們要做的第一件事情就是定義我們的終端類型協議。這個協議要包含用於配置終端的所有信息。什麼是終端?本質上來講它是一個包含各種組件比如頭文件(headers),查詢參數(query parameters),體參數(body parameters)的URL請求(URLRequest)。終端類型協議是我們網路層實現的基石。我們建一個文件,並命名EndPointType,把它放到服務組中(不是終端組,後面我們分清楚的)。

終端類型協議

HTTP協議

為了創建一個完整的終端,我的終端類型協議里有很多HTTP協議。讓我們看看這些協議需要什麼。

HTTP方法

創建一個名為HTTPMethod的文件並把它放在服務組中。這個枚舉會用於設置我們請求用的HTTP方法。

HTTPMethod枚舉

HTTP任務

創建一個名為HTTPTask的文件並把它放在服務組中。HTTPTask用於為一個特定的終端配置參數,你可以添加適當數量的案例(cases)到你的網路層請求中。我會按下圖建立我的請求,它只包含3個案例

HTTPTask 枚舉

在下一章我們會討論參數和如何處理參數的編碼。

HTTP頭文件

HTTPHeaders是一個字典的別名(typealias)。你可以在你HTTPTask文件的開頭創建它。

參數與編碼

創建一個名為ParameterEncoding的文件並把它放在編碼組中。我們首先要定義一個參數的別名,通過它我們可以讓代碼更乾淨簡潔。

之後用一個靜態函數編碼定義一個協議參數編碼器(ParameterEncoder)。這種編碼方式含有2個參數,一個inout URLRequest和Parameters。(為了防止混淆,後面我會把函數參數稱為參量)。INOUT是一個swift關鍵詞,用於把一個參量定義為引用參量。通常變數作為值類型傳送給函數。通過在參量的開頭加上inout,我們把它定義為引用類型。要學更多關於雙向參量,你可以點擊這裡。參數編碼器協議會通過JSONParameterEncoder和URLPameterEncoder實現。

參數編碼器執行編碼參數的函數,這個方法會失敗,返回一個錯誤,因而我們需要處理它。

能夠返回一個自定的錯誤提示比標準錯誤提示會更有價值。我總是花很多時間去分析Xcode給的一些錯誤提示。有了自定的錯誤提示你就可以定義屬於自己的錯誤信息,就能清楚知道錯誤到底來自哪裡。為了做到這些,我創建了一個繼承自Error的枚舉。

NetworkError枚舉

URL參數編碼器(URLParameterEncoder)

創建一個名為URLParameterEncoder的文件並把它放在編碼組中。

URL參數編碼器代碼

上面的代碼含有一些參數,它可以將他們變成URL參數來安全傳遞。你要知道一些字元在URL中一些字元是禁用的。參數也被『&』標記分開,我們需要考慮到所有這些。如果之前沒有設置,我們還要為請求添加合適的頭文件。

這個示例代碼是使用單元測試時應該考慮到的。如果URL沒有正確建立,我們就會有很多不必要的錯誤。如果你在使用一個開放API,你一定不希望自己的請求配額被一堆錯誤測試用完。

JSON參數編碼器(JSONParameterEncoder)

創建一個名為JSONParameterEncoder的文件,也把它放在編碼組中。

JSON參數編碼器代碼

類似URL參數編碼器,不過這裡是為JSON編碼參數,同樣要添加合適的頭文件。

網路路由器(NetworkRouter)

創建一個名為NetworkRouter的文件並把它放在服務組中。我們從為一個完成部分(completion)定義別名開始。

之後我們定義一個協議網路路由器

NetworkRouter代碼

一個網路路由器有一個用於產生請求的終端,一旦請求產生,它會傳遞對完成部分的應答。我加入了一個取消函數,有它當然好,但不是一定要用到。這個函數可以在一個請求存在周期的任意時刻調用並取消它。如果你的應用有上傳或下載任務,這會很有用。為了讓我們的路由器能處理任何終端類型,我們這裡使用了關聯類型。如果不用關聯類型,路由器就不得不有一個具體的終端類型。

路由器

創建一個名為Router的文件並把它放在服務組中。我們聲明一個URLSessionTask類型的私有變數任務。這個任務本質上是整個工作要做的。我們讓這個變數私有化,因為我們不想任何這個類之外的任何東西會調整我們的任務。

Router方法存根

請求

這裡我們通過調用buildRequest生成我們的請求,並給它一個終端作為路徑。這個buildRequest的調用被限制在一個do-try-catch區塊,因為我們的編碼器可能會報出錯誤。我們僅僅把所有應答,數據和錯誤傳送給完成部分。

Request方法代碼

建立請求

在Router中創建一個名為buildRequest的私有函數,這個函數負責我們網路層中一切重要工作。本質上就是把EndPointType轉化為URLRequest。一旦我們的終端生成請求,我們可以把它傳遞給會話管理。這裡有很多工作要做,所以我們將會分別看看每個方法。讓我們分解buildRequest方法:

我們舉了一個URLRequest類型的變數請求的例子。把我們的基礎URL給它,並附上我們要用到的路徑。

我們設定這請求的httpMethod和我們終端的一致。

考慮到我們的編碼器會報告錯誤,我們創建一個do-try-catch區塊。只要創建一個大的do-try-catch區塊,我們就不需要為每次嘗試分別建一個。

開啟route.task

根據任務,調用合適的編碼器。

buildRequest方法代碼.

配置參數

在Router中創建一個名為configureParameters的函數

configureParameters方法的實現

這個函數負責為我們的參數編碼。因為我們的API要求所有的bodyParameters都是JSON,並且URLParameters是URL編碼的,我們把合適的參數傳遞給設計好的編碼器。如果你正在用一個有多種編碼方式的API,我建議修改HTTPTask來使用編碼器枚舉。這個枚舉需要包含所有你需要的不同類型編碼器。之後在configureParameters添加一個關於你編碼枚舉的附加參量。開啟這個枚舉,合適地為參數編碼。

添加附加頭文件

在Router中創建一個名為addAdditionalHeaders的函數

addAdditionalHeaders方法的實現

添加所有附加頭文件,讓它們成為請求頭文件的一部分。

取消

取消函數的實現是這樣的:

Cancel方法的實現

實踐

現在讓我們用一個實際例子看看我們建立的網路層。我們將從TheMovieDB獲取一些電影數據到我們的應用。

電影終端(MovieEndPoint)

電影終端與我們在Getting Started with Moya中提到的目標類型很相似。與實現Moya中目標類型不同的是這裡我們實現我們自己的終端類型。把這個文件放在終端組中。

終端類型

電影模式(MovieModel)

因為對TheMovieDB的回應同樣是JSON,我們的電影模式也不會改變。我們用可解碼協議來把JSON轉化為我們的模式。把這個文件放在模式組中。

電影模式

網路管理員

創建一個名為NetworkManager的文件並把它放在管理員組中。

現在開始我們的網路管理員將僅有2個靜態屬性:你的API密碼和網路環境(引用MovieEndPoint)。網路管理員也有一個類型為MovieApi的Router。

網路管理員代碼

網路響應

在NetworkManager中創建一個名為NetworkResponse的枚舉。

NetworkResponse枚舉

我們將用這個枚舉處理來自API的響應,並顯示相應的信息。

結果

在NetworkManager中創建一個枚舉Result。

Result枚舉

一個結果枚舉可以用在很多不同事情上,非常有用。我們根據結果確定我們對API的調用是成功還是失敗。如果失敗了,我們會返回一個錯誤信息並說明原因。

處理網路響應

創建一個名為handleNetworkResponse的函數,這個函數有一個參量,即HTTPResponse,並返回一個Result.


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 Cocoa開發者社區 的精彩文章:

又要跳票!蘋果跨平台應用推遲到2019年問世
iOS crash 日誌堆棧解析

TAG:Cocoa開發者社區 |