objc系列譯文(5.4):忘記NSURLConnection,擁抱NSURLSession吧!

ylovesy發表於2013-12-08

說到 iOS 7 和 Mac OS X 10.9 Mavericks 的顯著變化,其中一個就是Foundation框架中URL載入系統的優化。

此時可能有人正沉浸在Apple的網路基礎架構,我想在這裡分享一下我對這些新APIs的看法,並展示這些新APIs如何改變我們構建應用程式的方式,以及這些它們在API設計理念演變中的意義。

作為Core Foundation / CFNetwork 框架的APIs之上的一個抽象,NSURLConnection伴隨著2003年Safari瀏覽器的原始發行版本,誕生於10年前。NSURLConnection這個名字,實際上指的是一組構成Foundation框架中URL載入系統的相互關聯的元件:NSURLRequest,NSURLResponse,NSURLProtocol,NSURLCache,NSHTTPCookieStorage,NSURLCredentialStorage,以及和它同名的NSURLConnection。

NSURLRequest物件被傳遞給一個NSURLConnection物件。委託(遵守從前的非正式<NSURLConnectionDelegate> 和  <NSURLConnectionDataDelegate>協議)作為一個NSURLResponse非同步響應,任何相關的NSData從伺服器傳送。

一個請求傳送到伺服器前,共享的快取記憶體先被訪問,然後根據策略(policy)和可用性(availability),一個快取的響應可能立即透明地返回,如果所有快取的響應都不可用,則該請求根據選項,被用於為任何後續請求快取它的響應。

在協商傳送一個請求到伺服器的過程中,該伺服器可發出驗證質詢,這可以由共享的cookie,證書儲存(credential storage)或通過連線委託自動處理。必要的時候,為了無縫地改變裝載行為,傳出請求也可以被註冊的NSURLProtocol物件截獲。

不管怎樣,考慮到NSURLConnection作為一個網路基礎架構,成千上萬的Cocoa和Cocoa Touch應用程式從中獲益,它已經表現得相當好。但是,這些年來,iPhone和iPad新興的用例,特別是有一些已經向NSURLConnection的幾個核心設想提出了挑戰,對其重構已經迫在眉睫。

在2013年的WWDC上,Apple揭開了NSURLConnection繼任者的面紗:NSURLSession。

Screen Shot 2013-12-04 at 10.28.52 AM

與NSURLConnection類似,除了同名類NSURLSession,NSURLSession也是指一組相互依賴的類。NSURLSession包括與之前相同的元件,例如NSURLRequest, NSURLCache等。NSURLSession的不同之處在於,它把 NSURLConnection替換為NSURLSession, NSURLSessionConfiguration,以及3個NSURLSessionTask的子類:NSURLSessionDataTask, NSURLSessionUploadTask, 和NSURLSessionDownloadTask.

與NSURLConnection相比,NSURLSession最直接的改善就是提供了配置每個會話的快取,協議,cookie和證書政策(credential policies),甚至跨應用程式共享它們的能力。這使得框架的網路基礎架構和部分應用程式獨立工作,而不會互相干擾。每一個NSURLSession物件都是根據一個NSURLSessionConfiguration初始化的,該NSURLSessionConfiguration指定了上面提到的政策,以及一系列為了提高移動裝置效能而專門新增的新選項。

NSURLSession的另一重要組成部分是會話任務,它負責處理資料的載入,以及客戶端與伺服器之間的檔案和資料的上傳下載服務。NSURLSessionTask與NSURLConnection是及其相似的,因為它負責載入資料,而主要的區別在於,任務共享它們父類NSURLSession的共同委託(common delegate)。

我們現在首先深入探討任務,然後再介紹更多關於會話配置的知識。

 

NSURLSessionTask

NSURLSessionTask是一個抽象子類,它有三個具體的子類是可以直接使用的:NSURLSessionDataTask,NSURLSessionUploadTask和NSURLSessionDownloadTask。這三個類封裝了現代應用程式的三個基本網路任務:獲取資料,比如JSON或XML,以及上傳下載檔案。

NSURLSession

 

當一個NSURLSessionDataTask完成時,它具有關聯的資料,而一個NSURLSessionDownloadTask完成時,它具有一個已下載檔案的臨時檔案路徑。 NSURLSessionUploadTask 繼承了 NSURLSessionDataTask,因為伺服器響應一個上傳請求時,往往伴隨著相關聯的資料。 所有任務均可撤銷,也可以暫停和恢復。當一個下載任務被取消時,它可以選擇建立恢復資料,然後可以傳遞給下一次新建立的下載任務,以便繼續之前的下載。

不同於直接使用alloc-init‘d初始化方法,任務是由一個NSURLSession建立的。每個任務的構造方法都對應一個版本,有或者沒有completionHandler屬性,例如:–dataTaskWithRequest: 和  –dataTaskWithRequest:completionHandler:。這與NSURLConnection的 -sendAsynchronousRequest:queue:completionHandler:類似,通過指定completionHandler屬性建立並使用一個隱含的委託,而不是使用任務的會話。在任何一種任務會話委託的預設行為需要被重寫的情況下,這種不太方便的非completionHandler的變體將需要被使用。

 

Constructors

iOS5中,NSURLConnection新增了sendAsynchronousRequest:queue:completionHandler:方法,這大大簡化了一次性請求的使用,同時可以作為sendSynchronousRequest:returningResponse:error::的非同步替代品。

NSURLSession與它的任務構造方法在此模式上迭代。在執行resume方法前,該任務物件為了進行進一步的配置而返回,而不是立即執行resume方法。

資料任務可以通過NSURL或NSURLRequest建立(前者是一個標準GET請求URL的快捷方式)。

上傳任務也可以通過一個請求以及一個需要上傳的本地檔案的URL對應的NSData物件建立。

下載任務也需要一個請求,但不同之處在於它們的completionHandler。資料和上傳任務在完成時立即返回,但下載任務將資料寫入本地的臨時檔案。completionHandler有責任將檔案從它的臨時位置移動到一個永久位置,這個永久位置就是塊的返回值。

NSURLSession & NSURLConnection Delegate Methods

總體而言,NSURLSession的委託方法,是NSURLConnection的演化的十年中 ad-hoc 模式出現以來的一個顯著改善。對於一個完整的概述,可以檢視此對映表

以下是一些具體的觀察:

NSURLSession同時具有用來處理身份驗證挑戰會話和任務委託方法。這個會話的委託方法處理連線級別的問題,如伺服器信任和客戶端證書的評估,NTLM和Kerberos,而任務的委託處理以請求為基礎的挑戰,如Basic, Digest, 或者代理身份驗證。

NSURLConnection由兩個方法可以表明一個請求已經完成(NSURLConnectionDataDelegate -connectionDidFinishLoading: 和 NSURLConnectionDelegate -connection:didFailWithError:),而NSURLSession只有一個委託方法(NSURLSessionTaskDelegate -URLSession:task:didCompleteWithError:)。

與NSURLConnection使用的 long long型別相比,委託方法指定在NSURLSession中一定數量的位元組傳輸使用int64_t型別的引數。

NSURLSession在Foundation框架對於委託方法的completionHandler:引數使用上 ,引入了一種新的模式。這允許委託方法可以安全地在主執行緒以非阻塞方式執行;委託可以簡單地在後臺執行dispatch_async ,然後在完成時呼叫completionHandler。同時,它可以有效地擁有多個返回值,不需要使用笨拙的引數指標。就NSURLSessionTaskDelegate的URLSession:task:didReceiveChallenge:completionHandler:方法而言,completionHandler接受兩個引數:身份驗證質詢的處理( the authentication challenge disposition)以及需用使用的證書(如果適用)。

想要檢視更多關於會話任務的資訊,可以檢視 WWDC Session 705: “What’s New in Foundation Networking”

 

NSURLSessionConfiguration

NSURLSessionConfiguration物件用於初始化NSURLSession物件。展開請求級別中與NSMutableURLRequest相關的可供選擇的方案,我們可以看到NSURLSessionConfiguration對於會話如何產生請求,提供了相當多的控制和靈活性。從網路訪問效能,到cookie,安全性,快取策略,自定義協議,啟動事件設定,以及用於移動裝置優化的幾個新屬性,你會發現你一直在尋找的,正是NSURLSessionConfiguration。

會話在初始化時複製它們的配置,NSURLSession有一個只讀的配置屬性,使得該配置物件上的變化對這個會話的政策無效。配置在初始化時被讀取一次,之後都是不會變化的。

 

Constructors

NSURLSessionConfiguration有三個類建構函式,這很好地說明了NSURLSession是為不同的用例而設計的。

+ defaultSessionConfiguration返回標準配置,這實際上與NSURLConnection的網路協議棧是一樣的,具有相同的共享NSHTTPCookieStorage,共享NSURLCache和共享NSURLCredentialStorage。

+ ephemeralSessionConfiguration返回一個預設配置,沒有永續性儲存的快取,Cookie或證書。這對於實現像祕密瀏覽功能的功能來說,是很理想的。

+ backgroundSessionConfiguration:獨特之處在於,它會建立一個後臺會話。後臺會話不同於常規的,普通的會話,它甚至可以在應用程式掛起,退出,崩潰的情況下執行上傳和下載任務。初始化時指定的識別符號,被用於向任何可能在程式外恢復後臺傳輸的守護程式提供上下文。

想要檢視更多關於後臺會話的資訊,可以檢視WWDC Session 204: “What’s New with Multitasking”

 

Properties

NSURLSessionConfiguration擁有20個屬性。熟練掌握這些屬性的用處,將使應用程式充分利用其網路環境。

 

General

HTTPAdditionalHeaders指定了一組預設的可以設定出站請求的資料頭。這對於跨會話共享資訊,如內容型別,語言,使用者代理,身份認證,是很有用的。

networkServiceType對標準的網路流量,網路電話,語音,視訊,以及由一個後臺程式使用的流量進行了區分。大多數應用程式都不需要設定這個。

allowsCellularAccess 和 discretionary 被用於節省通過蜂窩連線的頻寬。建議在使用後臺傳輸的時候,使用discretionary屬性,而不是allowsCellularAccess屬性,因為它會把WiFi和電源可用性考慮在內。

timeoutIntervalForRequest 和 timeoutIntervalForResource指定了請求以及該資源的超時時間間隔。許多開發人員試圖使用timeoutInterval去限制傳送請求的總時間,但這誤會了timeoutInterval的意思:報文之間的時間。timeoutIntervalForResource實際上提供了整體超時的特性,這應該只用於後臺傳輸,而不是使用者實際上可能想要等待的任何東西。

HTTPMaximumConnectionsPerHost 是 Foundation 框架中URL載入系統的一個新的配置選項。它曾經被用於NSURLConnection管理私人連線池。現在有了NSURLSession,開發者可以在需要時限制連線到特定主機的數量。

HTTPShouldUsePipelining 也出現在NSMutableURLRequest,它可以被用於開啟HTTP管道,這可以顯著降低請求的載入時間,但是由於沒有被伺服器廣泛支援,預設是禁用的。

sessionSendsLaunchEvents 是另一個新的屬性,該屬性指定該會話是否應該從後臺啟動。

connectionProxyDictionary指定了會話連線中的代理伺服器。同樣地,大多數面向消費者的應用程式都不需要代理,所以基本上不需要配置這個屬性。

關於連線代理的更多資訊可以在 CFProxySupport Reference 找到。

 

HTTPCookieStorage 是被會話使用的cookie儲存。預設情況下,NSHTTPCookieShorage的+ sharedHTTPCookieStorage會被使用,這與NSURLConnection是相同的。

HTTPCookieAcceptPolicy 決定了該會話應該接受從伺服器發出的cookie的條件。

HTTPShouldSetCookies 指定了請求是否應該使用會話HTTPCookieStorage的cookie。

 

Security Policies

URLCredentialStorage 是會話使用的證書儲存。預設情況下,NSURLCredentialStorage 的+ sharedCredentialStorage 會被使用使用,這與NSURLConnection是相同的。

TLSMaximumSupportedProtocol 和 TLSMinimumSupportedProtocol 確定是否支援SSLProtocol版本的會話。

 

Caching Policies

URLCache 是會話使用的快取。預設情況下,NSURLCache 的+ sharedURLCache 會被使用,這與NSURLConnection是相同的。

requestCachePolicy 指定了一個請求的快取響應應該在什麼時候返回。這相當於NSURLRequest 的-cachePolicy方法。

 

Custom Protocols

protocolClasses是註冊NSURLProtocol類的特定會話陣列。

 

總結

iOS 7 和 Mac OS X 10.9 Mavericks 中URL載入系統的變化,是NSURLConnection的一個深思熟慮而自然的進化。總體而言,Foundation框架團隊做出了令人驚訝的工作,他們研究並預測了移動開發者現有的和新興的用例,創造了能夠滿足日常任務的, 真正有用的APIs。

就可組合性和可擴充套件性而言,儘管在會話任務的體系結構中,某些決定是一種倒退,NSURLSession仍然可以很好地作為更高階別的網路功能的一個基礎。

相關文章