本文由CocoaChina--BYB_1132(論壇ID)翻譯
原文:Thoughts On AlamoFire--Swift’s AFNetworking Implementation
HTTP協議就是現代開發的同義詞,對於有經驗的iOS開發者來說, 熟悉並盡可能使用這些流行的協議是日常工作的基礎。
不出意料,iOS 應用在這一點上沒有什麼不同,成千上萬的app和工程師都依靠廣受歡迎的AFNetworking 庫實現與服務器的交互,JSON解析, 以及提供占位符圖片等多個功能。
簡言之,做到這些並不容易。這篇文章中我們了要解的是Alamofire庫。
基礎
Alamofire的核心主要是試圖簡化iOS中HTTP網絡連接, 它通過使用NSURLSession以及Foundation URL Loading System來創建一個Swift本地的網絡訪問接口,從而實現令人難以置信效率的任務。
Swift放棄了代理模式取而代之的使用了回調。對於我而言,我喜歡這個選擇。然而基礎承諾機制模式(promise-based patterns)也能起到一定作用, 它們也隱藏了一些壞代碼味道,對於一些人有點太神奇了。
進一步看,它是異步實現的。你也許聽說過,但是在主線程上執行網絡調用並不是一個好主意,不過Alamofire采用了許多創造性的最優方法。
例如,通過NSURLCache處理緩存來阻止不必要的訪問請求。另外,如果HTTP狀態碼在可接受的范圍內(200-300),就可以利用其豐富的鏈路模式通過少量代碼去做大量有意義的工作。
歷史總在重復
Alamofire 也承續了AFNetworing使用者所熟悉的模式,一些處理方法也不同於它的前身,主要因為Alamofire是為了Swift而創建的。
例如, AFNetworking 調用子類AFHTTPSessionManager來使用每個API。也有例外,比如用NSURLSession替換NSURLConection。
Alamofire 通過遵守URLRequestConvertible協議創建一個路由Router來調用了類似的方法, 在底層,Alamofire 使用單例模式來創建在 NSURLSessionConfiguration.的頂層
初體驗
我們開始吧
Alamofire.request(.GET, “http://www.telize.com/jsonip?callback=getip").response {(request, response, data, error) in println(request + response + error) }
像AFNetworking 和其他的HTTP網絡庫一樣,Alamofire提供了簡單、易用的方法來快速隨性的使用網絡請求。這種特定的網絡GET請求會返回一個請求對象,這個對象可以依附實現所有的HTTP過程的方法。
在Alamofire中,默認的行為規范是從服務器響應積累到的NSData(數據),我通過一個閉包來鏈接一個響應處理程序來解析響應,或者但願對任何錯誤的響應不會發生在請求過程中。
響應
響應通過HTTP用不同的形式顯現,最受青睐的毫無疑問是JSON, JSON是XML的衍生品,相對XML更年輕更健壯。Alamofire對JSON型數據很友好。
Alamofire.request(.GET, “http://httpbin.org/get").responseJSON {(request, response, JSON, error) in println(JSON) }
有一系列簡單的JSON字符串作為指定的響應返回數據
我們繼續
在Alamofire中, 鏈接在其框架的使用中很底層, 每當想到在OC中用方括號去定義類,讓人或高興或無奈。
Swift 像其他大多數高級語言一樣, 通過簡單的"."來調用函數, Alamofire 可以管理很多響應處理程序,而且一旦服務器返回響應它都會異步執行。
和往常一樣, 看示例最可靠:
Alamofire.request(.GET, “http://httpbin.org/get") .authenticate(HTTPBasic: user, password: password) .progress { (bytesRead, totalBytesRead, totalBytesExpectedToRead) in println(totalBytesRead) }.responseJSON { (request, response, JSON, error) in println(JSON) }.responseString { (request, response, string, error) in println(string) }
參數
當然, 如果HTTP網絡請求缺少了POST請求或查詢指定的訪問請求的能力就沒那麼令人期待了。
Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["key": "value"])
在Alamofire需要內嵌一個包含參數的一個字典, 如果你不指向特定的參數, 將傳入nil。對於編碼來說也是一樣的, 在網絡請求函數這是第四個參數.
枚舉
如果有人已經使用過swift, 它們可能發現枚舉在Swift 中是如此的好用。在 Objective-C中,即使有現代化的NS_ENUM,它仍然只是允許定義整數聲明。
Swift 還有很多小技巧
Alamofire充分擁有這些技巧, 因此在一個HTTP通信中所有的編碼參數邏輯都是用參數編碼(ParameterEncoding)枚舉實現, 所有的HTTP verbs都以 RFC 2616 §9 定義, 如下:
public enum Method: String { case OPTIONS = “OPTIONS” case GET = “GET” case HEAD = “HEAD” case POST = “POST” case PUT = “PUT” case PATCH = “PATCH” case DELETE = “DELETE” case TRACE = “TRACE” case CONNECT = “CONNECT” }
同時,如果你好奇Swift枚舉強大的功能, 免費下載 swift starter guide。請原諒我做的這個小廣告。
路由
創建一個網絡訪問路由是實現的關鍵, 在這裡將定義一些共同的用於同一個 API 的端點, 通過一個遵循URLRequestConvertible的枚舉來創建一個路由。
當一個枚舉遵循URLRequestConvertible時, 它需要包含一個叫做URLRequest的變量, 這個變量必須是NSURLRequest類型.
對於HTTP網絡庫的通常做法發生在這裡, 使用者極大可能定義一個靜態字符串來代表一個基礎的URL以及API key/consumer secret.
記住,在現實世界中最好不要將這些內容放到源代碼周圍。我個人選擇plist文件。
在任何情況下……
工作流如下:
定義一個基本的URL
通過在枚舉中的case語句定義端口(例如 Users, Comments等等)
URLRequest初始化並通過一個跟蹤閉包設置。在閉包中, 增加參數並構造端點。
URL、URLRequest 和編碼都占一個完全的網絡請求發送到服務器
多讀幾遍這個, 首先, 我認為這點有些不合理---一個函數實現過多的功能
在實踐中,它運作得很好:
enum APIRouter: URLRequestConvertible { static let BASE_URL = //base url static let API_KEY = //api key, consumer secret for OAuth, etc case User(Int) case ProfilePicture(Int, Size) case Likes(Int, Int) var URLRequest: NSURLRequest { let (path: String, parameters: [String: AnyObject]) = { switch self { case .User (let page): let params = []//Provide params return (“/user”, params) case .ProfilePicture(let id, let size): var params = [] return (“/profilepictures/\(id)”, params) case .Likes(let id, let commentsPage): var params = [] return (“/likes/\(id)/user”, params) } }() let URL = NSURL(string: APIRouter.BASE_URL) let URLRequest = NSURLRequest(URL:URL!.URLByAppendingPathComponent(path)) let encoding = Alamofire.ParameterEncoding.URL return encoding.encode(URLRequest, parameters: parameters).0 } }
一個強有力的例子, 但是我選擇把代碼展示的更形象些。
豐富的功能
Alamofire有許多讓程序猿信服去使用它的理由。在iOS開發中,使用NURLSession是HTTP網絡的未來趨勢, 相比NSURLConnection來說,它的功能更加豐富:
後台上傳和下載
暫停以及重新開始網絡操作的能力
可配置的容器(Container)
子類和私有存儲
改進的認證處理
對每個基礎連接進行身份驗證
多種代理模式--NSURLConnection擁有異步代碼塊的基本方法, 但是不能用它們的代理,NSURLSession具有一種混合型的方法。
我認為大家都同意這是正確的選擇, 如果有人對AFNetworking 能做而Alamofire不能做的感興趣的話,那麼有以下幾點:
UIKit 擴展
TLS驗證
NSOperation/NSURLConnection/AFURLConnectionOperation調用
可達性(Reachability)
多重HTTP網絡請求構架
根據使用情況決定, 需要使用這些特點的要麼是破壞游戲規則的人,要麼是不在乎的人。
總結
在這一點上,部分工程師爭論認為NSURLSession讓AFNetworking變成了一個華麗的封裝。這可能在某種程度上是正確的,但即使如此--這是一件壞事嗎?
它在簡化和抽象方面做的很好,雖然它不包含AFNetworking可以做的所有功能,但是這是 Swift 中 HTTP 網絡的一個良好開端。