爲什麼要使用NSURLSession

爲什麼要使用NSURLSession?

翻譯原文 ,所有版權規其所有。

well,先來看一些優點:

  • 後臺上傳和下載:只需在創建NSURLSession的時候配置一個選項,就能得到後臺網絡的所有好處。這樣可以延長電池壽命,並且還支持UIKit的多task,在進程間使用相同的委託模型。
  • 能夠暫停和恢復網絡操作:使用NSURLSession API能夠暫停,停止,恢復所有的網絡任務,再也完全不需要子類化NSOperation.

  • 可配置的容器:對於NSURLSession裏面的requests來說,每個NSURLSession都是可配置的容器。舉個例來說,假如你需要設置HTTP header選項,你只用做一次,session裏面的每個request就會有同樣的配置。

  • 提高認證處理:認證是在一個指定的連接基礎上完成的。在使用NSURLConnection時,如果發出一個訪問,會返回一個任意的request。此時,你就不能確切的知道哪個request收到了訪問。而在NSURLSession中,就能用代理處理認證。

  • 豐富的代理模式:在處理認證的時候,NSURLConnection有一些基於異步的block方法,但是它的代理方法就不能處理認證,不管請求是成功或是失敗。在NSURLSession中,可以混合使用代理和block方法處理認證。

  • 上傳和下載通過文件系統:它鼓勵將數據(文件內容)從元數據(URL和settings)中分離出來。

NSURLSession vs NSURLConnection

“哇喔,看起來NSURLSession好複雜!”,你可能會這樣想。“還是堅持用NSURLConnection吧。”

別擔心 — 使用NSURLSession處理簡單task就如使用NSURLConnection一樣容易。例如,我們使用一個簡單的網絡調用,來得到倫敦最新天氣的JSON數據。

假設你有這樣一個URL字符串:

NSString *londonWeatherUrl = @"http://api.openweathermap.org/data/2.5/weather?q=London,uk" ;

首先,使用NSURLConnection會這麼做:

NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:londonWeatherUrl]];
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response,
                   NSData *data,
                   NSError *connectionError) {
  // handle response
  }];  

那來看下NSURLSession是怎麼做的。這個是NSURLSession使用的最簡單方法。隨後你還會看到怎樣配置session,設置其他的特性,比如代理。

NSURLSession *session = [NSURLSession sharedSession];
[[session dataTaskWithURL:[NSURL URLWithString:londonWeatherUrl]
      completionHandler:^(NSData *data,
                          NSURLResponse *response,
                          NSError *error) {
        // handle response
}] resume];  

注意,你不需要指定運行哪個隊列,默認會開闢一個後臺線程。如果有兩個的話,這種設計可能就比較難區分之間的不同。蘋果官方旨在使用dataTaskWithURL來代替NSURLConnection中的sendAsynchronousRequest

看吧,NSURLSession就如NSURLConnection一樣易用,並且還有一些額外的功能。


NSURLSession vs AFNetworking

說到網絡請求不得不說的就是AFNetworking Framework。這是iOS/OS X上最流行的框架之一,由Mattt Thompson創建。

注意:學習AFNetworking,可以在github頁面上找到,https://github.com/AFNetworking/AFNetworking,你還可以看這篇教程http://www.raywenderlich.com/30445/afnetworking-crash-course

下面是對於同樣的數據請求,AFNetworking 1.x的代碼:

NSURLRequest *request = [NSURLRequest requestWithURL:
                     [NSURL URLWithString:londonWeatherUrl]];

AFJSONRequestOperation *operation =
[AFJSONRequestOperation JSONRequestOperationWithRequest:request
success:^(NSURLRequest *request,
          NSHTTPURLResponse *response,
          id JSON) {
// handle response
} failure:nil];
[operation start];  

使用AFNetworking的好處之一是,它的處理響應數據是數據類型類,AFJSONRequestOperation(或類似XML,plist)的返回成功的block裏面已經解析出了你要的數據。而NSURLSession接收到的是NSData類型,你需要把它再轉換成JSON類型。

注意:用NSJSONSerialization可以輕鬆的將NSData類型轉換爲JSON類型。

那麼,你是喜歡用AFNetworking還是NSURLSession呢?
個人認爲,簡單的需求最好用NSURlSession-這可減少工程裏面第三方庫的依賴。當然了,現在AFNetworking也添加了新的代理,配置,基於task的API等等特性。

如果你使用了AFNetworking2.0的新特性,比如系列化,並且還集成了UIKit(加入了一些UIImageView的類目方法),現在就很難說服你不用它了。

注意:在AFNetworking2.0的分支,他們已經轉成使用NSURLSession。  
https://github.com/AFNetworking/AFNetworking/wiki/AFNetworking-2.0-Migration-Guide

譯者注:中間這裏有一部分講到了Dropbox,這裏就不翻譯了。對於Dropbox,國內牆得厲害,完全打不開。

NSURLSession 類套(suite of classes)

蘋果公司描述了新類NSURLSession,及其類套。包括新的上傳,下載,處理認證等工具,能處理http協議中的所用事情。

在編碼前,重要的先理解它們是怎樣協同工作的。

NSurLSessionNSuRLSessionConfiguration和可選代理(optional delegate)構成。再根據你的網絡需求通過NSURLSessionTask來創建session。


NSURLSessionConfiguration

有三個方法用來創建NSURLSessionConfiguration:

  • defaultSessionConfiguration- 使用全局的cache,cookie和credential storage objects來創建configuration對象。

  • ephemeralSessionConfiguration – 這個configuration用於“private” sessions,還有對於cache, cookie, or credential storage objects的非永久存儲。

  • backgroundSessionConfiguration – 做遠程push通知或是應用程序掛起的時候就要用到這個configuration。

一旦創建了NSURLSessionConfiguration就可以給它設置各種屬性:

NSURLSessionConfiguration *sessionConfig =
[NSURLSessionConfiguration defaultSessionConfiguration];

// 1
sessionConfig.allowsCellularAccess = NO;

// 2
[sessionConfig setHTTPAdditionalHeaders:
      @{@"Accept": @"application/json"}];

// 3
sessionConfig.timeoutIntervalForRequest = 30.0;
sessionConfig.timeoutIntervalForResource = 60.0;
sessionConfig.HTTPMaximumConnectionsPerHost = 1;
  1. 限制了網絡只能是wifi。
  2. 設置了所有的請求只接收JSON數據
  3. 配置網絡超時,限制一個主機只有一個網絡連接。

這裏僅僅只做了一些簡單的配置,看文檔去了解更多的屬性吧。


NSURLSession

NSURLSession是爲了代替NSURLConnection而設計的。Sessions的所有工作都是通過它的小弟,也就是NSURLSessionTask的對象。可以用block,delegate,或者兩者混合來創建task。舉個例子,你要下載圖片,就要創建NSURLSessionDownloadTask

首先需要創建session:

// 1
NSString *imageUrl =
@"http://www.raywenderlich.com/images/store/    iOS7_PDFonly_280@2x_authorTBA.png";

// 2
NSURLSessionConfiguration *sessionConfig =[NSURLSessionConfiguration defaultSessionConfiguration];

// 3
NSURLSession *session =[NSURLSession sessionWithConfiguration:sessionConfig
                            delegate:self
                       delegateQueue:nil];

ok,這個看上去和前面的只有點不同,一步一步看:

  1. 這裏下載一張圖片(譯者改:原文匪夷所思)。
  2. 創建NSURLConfiguration
  3. 用當前類對象作爲代理創建session。

之後,通過創建帶有完成處理的task來下載圖片:

// 1
NSURLSessionDownloadTask *getImageTask =
[session downloadTaskWithURL:[NSURL URLWithString:imageUrl]

completionHandler:^(NSURL *location,
                    NSURLResponse *response,
                    NSError *error) {
// 2
UIImage *downloadedImage =
      [UIImage imageWithData:
          [NSData dataWithContentsOfURL:location]];
//3
dispatch_async(dispatch_get_main_queue(), ^{
    // do stuff with image
    _imageWithBlock.image = downloadedImage;
  });
  }];

// 4
[getImageTask resume];  

很好,現在看起來像網絡請求代碼了!

  1. task由session創建。上面是創建了一個基於block的方法。你還可以用NSURLSessionDownloadDelegate跟蹤下載進度:

     -URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:  
    
  2. 通過location變量來得到image指針。

  3. 然後是更新UIImageView的圖片。
  4. 開始這個task。
  5. session能夠輕鬆的創建task,併發送到代理方法,通知你完成。

這是像上面使用相同的session:

// 1
NSURLSessionDownloadTask *getImageTask = [session downloadTaskWithURL:[NSURL URLWithString:imageUrl]];

[getImageTask resume];  
  1. 如果你接下來什麼都不做的話,我們就使用這些代碼。那麼,就需要實現這個協議中的代理方法NSURLSessionDownloadDelegate。首先是,收到下載完成的通知:

     -(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { 
     // use code above from completion handler 
     }  
    

這裏再一次給你提供了location,然後用它就能獲取image。

最後,如果需要跟蹤下載進度:

-(void)URLSession:(NSURLSession *)session
     downloadTask:(NSURLSessionDownloadTask *)downloadTask
     didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
  NSLog(@"%f / %f", (double)totalBytesWritten,
(double)totalBytesExpectedToWrite);
}  


NSURLSessionTask


上面看了NSURLSessionDataTaskNSURLSessionDownloadTask的使用。這兩個都是繼承至NSURLSessionTask

NSURLSessionTask是session中task的基類,它們只能由session或session的子類創建。

NSURLSessionDataTask

這個task調用HTTP GET請求從服務器獲取數據。返回的數據格式是NSData。可能需要你自己轉換成XML,JSON,UIimage等..

NSURLSessionDataTask *jsonData = [session dataTaskWithURL:yourNSURL
  completionHandler:^(NSData *data,
                      NSURLResponse *response,
                      NSError *error) {
    // handle NSData
}];  

NSURLSessionUploadTask

這個類是上傳用的,在數據傳輸過程中,這個代理方法能觀察網絡狀況。
上傳一張圖片:

NSData *imageData = UIImageJPEGRepresentation(image, 0.6);

NSURLSessionUploadTask *uploadTask = [upLoadSession uploadTaskWithRequest:request fromData:imageData];

這個task由session創建,上傳圖片的NSData。其他上傳方法還有上傳文件,或是數據流。

NSURLSessionDownloadTask

NSURLSessionDownloadTask下載文件更簡單,可以在下載中掛起,恢復。它有一點點不同於其他兩個子類。

  1. task的類型直接寫到一個臨時文件中。
  2. 下載過程中會調用URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite: 去更新狀態。
  3. 當task完成,URLSession:downloadTask:didFinishDownloadingToURL:會被調用。此時你可以將臨時文件保存到永久文件中。
  4. 下載失敗或是取消還可以得到已經下載的那一部分數據。

使用這個掛起task:

[uploadTask resume];  

同時管理多個task時,可以用taskIdentifier屬性來唯一標識task。

well,現在瞭解了NSURLSession類套中主要的類。

後面還有一部分,還是與Dropbox有關的,就不再翻譯了。

轉載請註明出處。

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