NSURLConnection被棄用,請用NSURLSession(轉)

說到 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。

  

  與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,以及上傳下載文件。

  

  當一個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::的異步替代品。

 NSURL *URL = [NSURL URLWithString:@"http://example.com"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 [NSURLConnection sendAsynchronousRequest:request
                                    queue:[NSOperationQueue mainQueue]
                        completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
     // ...
 }];

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

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

 NSURL *URL = [NSURL URLWithString:@"http://example.com"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                         completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         // ...
     }];

 [task resume];

  上傳任務也可以通過一個請求以及一個需要上傳的本地文件的URL對應的NSData對象創建。

NSURL *URL = [NSURL URLWithString:@"http://example.com/upload"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];
 NSData *data = ...;

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request
                                                            fromData:data
                                                   completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         // ...
     }];

 [uploadTask resume];

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

NSURL *URL = [NSURL URLWithString:@"http://example.com/file.zip"];
 NSURLRequest *request = [NSURLRequest requestWithURL:URL];

 NSURLSession *session = [NSURLSession sharedSession];
 NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
                                                         completionHandler:
    ^(NSURL *location, NSURLResponse *response, NSError *error) {
        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
        NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:documentsPath];
        return [documentsDirectoryURL URLByAppendingPathComponent:[[response URL] lastPathComponent]];
    }];

 [downloadTask resume];

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指定了一組默認的可以設置出站請求的數據頭。這對於跨會話共享信息,如內容類型,語言,用戶代理,身份認證,是很有用的。

NSString *userPasswordString = [NSString stringWithFormat:@"%@:%@", user, password];
NSData * userPasswordData = [userPasswordString dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64EncodedCredential = [userPasswordData base64EncodedStringWithOptions:0];
NSString *authString = [NSString stringWithFormat:@"Basic: %@", base64EncodedCredential];
NSString *userAgentString = @"AppName/com.example.app (iPhone 5s; iOS 7.0.2; Scale/2.0)";

configuration.HTTPAdditionalHeaders = @{@"Accept": @"application/json",
                                        @"Accept-Language": @"en",
                                        @"Authorization": authString,
                                        @"User-Agent": userAgentString};

  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仍然可以很好地作爲更高級別的網絡功能的一個基礎。




原文鏈接: Mattt Thompson 翻譯: 伯樂在線 - ylovesy
譯文鏈接: http://blog.jobbole.com/52477/
轉載必須在正文中標註並保留原文鏈接、譯文鏈接和譯者等信息。]


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章