NSURLSession

Using NSURLSession
NSURLSession API

會話類型

  1. default session:與其他下載URL的Foundation方法類似,使用基于磁盤的緩存策略,并在用戶的keychain中存儲證書
  2. Ephemeral session:不存儲任何數據到磁盤中,所有緩存、證書存儲都保存在RAM中并與會話綁定,應用結束會話時,這些都會被釋放
  3. background session:類似于default session,除了有一個獨立的進程進行來處理所有的數據傳輸。
  4. 還有個單例 shared session,沒有configuration。

任務類型

  1. data tasks:使用NSData對象來發送和接收數據。數據任務可以分片返回數據,也可以通過完成處理器一次性返回數據。由于數據任務不存儲數據到文件,所以不支持background session
  2. download tasks:以文件的形式接收數據,當程序不運行時支持后臺下載
  3. upload tasks:通常以文件的形式發送數據,支持background session

后臺傳輸

NSURLSession支持在應用掛起時在后臺傳輸數據,后臺傳輸只由使用background session配置的對象創建的會話進行調用,backgroundSessionConfigurationWithIdentifier:
使用后臺會話時,由于其是在一個獨立的進程中傳輸,且重啟應用進程相當損耗資源,只有少量特性可以使用,所以有以下限制:

  1. 會話必須提供事件分發(event delivery)代理
  2. 只支持http和https協議
  3. 總是伴隨重定向
  4. 只有從文件中upload tasks才可以,從data objects或者stream將會失敗
  5. 如果當應用在后臺時初始化的后臺傳輸,則配置對象的discretionary屬性為true

在iOS中,當我們的應用不再運行時,如果后臺下載任務完成或者需要證書,則系統會在后臺自動重啟我們的應用,同時調用UIApplicationDelegate對象的application:handlerEventsForBackgroundURLSession:completionHandler:方法。這個調用會提供啟動的應用的session的標識。我們的應用應當存儲completion handler,使用相同的標識來創建后臺配置對象,然后使用配置對象來創建會話。新的會話會與運行的后臺activity關聯。當會話完成后臺下載任務時,會給會話代理發送一個URLSessioinDidFinishEventsForBackgroundURLSession:消息。代理對象然后在main thread調用存儲的completion handler,這樣操作系統才知道再次暫停你的應用是安全的。
如果在程序掛起時有任何任務完成,則會調用URLSession:downloadTask:didFinishDownloadingToURL:方法。
同樣的,如果任務需要證書,則NSURLSession對象會在適當的時候調用URLSession:task:didReceiveChallenge:completionHandler: 和URLSession:didReceiveChallenge:completionHandler:方法。

會話和任務對象實現了NSCopying協議:

  1. 當應用拷貝一個會話或任務對象時,會獲取相同對象的指針(未創建新對象)
  2. 當應用拷貝一個配置對象時,會獲取一個可單獨修改的新的對象(創建新對象)

NSURLSession的生命周期

Life Cycle of a URL Session
中文翻譯

創建和配置NSURLSession

配置選項

  1. 支持對緩存、cookies、證書的私有存儲 ,以及對單例會話特定的protocol
  2. 關聯到一個特定請求(任務),或者一組請求(會話)的認證
  3. 可以通過url上傳或者下載文件
  4. 配置主機的最大連接數
  5. 當資源無法在一個確定時間內下載時,配置一個超時時間
  6. 支持安全傳輸協議TLS的版本區間
  7. 自定義代理字典
  8. cookie的控制策略
  9. HTTP的傳輸控制

因為大部分的配置都在一個configuration對象中設置,可以重用一些基本設置;你可以在任何時間安全的修改一個configuration對象。因為當創建一個會話時,configuration對象的傳遞是由深拷貝實現的,所以修改只會影響之后新創建的會話,不會對已存在的會話造成影響。初始化一個會話對象(session object)可以進行如下操作:

  1. 一個configuration對象用來管理會話或任務的行為
  2. optional:一個代理對象用來表示接收數據的進度,會話任務或會話其他事件的進度,比如服務器認證,決定一個加載請求是否可轉換為下載請求等等
  3. 如果沒有指定一個代理,NSURLSession對象將使用系統默認提供的代理。在這種方式中,你可以輕松的使用NSURLSession方法替代已存在的sendAsynchronousRequest:queue:completionHandler:方法

app在后臺傳輸數據,必須自定義代理

Demo——利用配置項創建NSURLSession

- (void)setUpSession
{
    NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSessionConfiguration *ephemeralConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:@"backgroundConfiguration"];
    
    //針對defaultConfiguration配置cache
    NSString *cacheDirectory =  NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
    NSString *cachePath = [cacheDirectory stringByAppendingString:@"myCache"];
    
    NSURLCache *cacheUrl = [[NSURLCache alloc]initWithMemoryCapacity:16384 diskCapacity:268435456 diskPath:cachePath];
    defaultConfiguration.URLCache = cacheUrl;
    defaultConfiguration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
    
    NSOperationQueue *operationQueue = [NSOperationQueue mainQueue];
    //創建session
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfiguration delegate:self delegateQueue:operationQueue];
    //...
}

使用系統提供的代理獲取資源

- (void)getDataWithSystemDefaultDelegate
{
    NSURLSessionConfiguration *defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    
    NSURLSession *sessionWithoutADelegate = [NSURLSession sessionWithConfiguration:defaultConfiguration];
    NSURL *url = [NSURL URLWithString:@"https://www.example.com/"];
    
    [[sessionWithoutADelegate dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        NSLog(@"Got response %@ with error %@.\n", response, error);
        NSLog(@"DATA:\n%@\nEND DATA\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
              }] resume];
}

使用自定義的代理獲取資源

需要實現如下2個方法:
URLSession:dataTask:didReceiveData:
URLSession:task:didCompleteWithError:

下載文件

app需要實現以下的代理方法

  1. URLSession:downloadTask:didFinishDownloadingToURL:提供下載內容臨時存儲的目錄地址。注意:在這個方法返回之前,必須打開文件來進行讀取或者將下載內容移動到一個永久目錄;當方法返回后,臨時文件將會被刪除。
  2. URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:提供下載的進度信息
  3. URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:告訴app嘗試恢復之前失敗的下載
  4. URLSession:task:didCompleteWithError:告訴app下載失敗
  1. 當下載任務安排在background session中時,當app停止運行時下載繼續;
  2. 如果是安排在default/ephemeral session中時,當重新開啟app時,下載會重新開始。
  3. 與服務器傳輸數據期間,如果用戶進行了暫停操作,app可以調用cancelByProducingResumeData:方法取消任務。然后,app可以將已傳輸的數據作為參數傳遞給downloadTaskWithResumeData:或者downloadTaskWithResumeData:completionHandler:來創建一個新的下載任務繼續下載。
    4)如果傳輸失敗,代理會調用URLSession:task:didCompleteWithError:。如果任務可以再運行,userInfo中包含鍵NSURLSessionDownloadTaskResumeData,可以將數據作為參數傳遞給downloadTaskWithResumeData:或者downloadTaskWithResumeData:completionHandler:來創建一個新的下載任務進行重試

上傳數據內容

app可以對Http post請求提供三種方式的請求體:NSData對象、文件、數據流

NSData上傳

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromData:(NSData *)bodyData;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromData:(NSData *)bodyData 
                                completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

file上傳

- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromFile:(NSURL *)fileURL;
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 
                                         fromFile:(NSURL *)fileURL 
                                completionHandler:(void (^)(NSData *data, NSURLResponse *response, NSError *error))completionHandler;

stream上傳

- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
- (void)URLSession:(NSURLSession *)session 
              task:(NSURLSessionTask *)task 
 needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler;

后臺任務

使用NSURLSession,當下載完成時,app將會自動啟動;代理中2個主要方法:

//負責創建session,存儲completionHandler
- (void)application:(UIApplication *)application 
handleEventsForBackgroundURLSession:(NSString *)identifier 
  completionHandler:(void (^)(void))completionHandler;
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session;
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容