NSURLSession使用說明及後臺工作流程分析

NSURLSession簡介

NSURLSession是iOS7中新的網絡接口,它與咱們熟悉的NSURLConnection是並列的。在程序在前臺時,NSURLSession與NSURLConnection可以互爲替代工作。注意,如果用戶強制將程序關閉,NSURLSession會斷掉。

NSURLSession提供的功能:

  • 通過URL將數據下載到內存
  • 通過URL將數據下載到文件系統
  • 將數據上傳到指定URL
  • 在後臺完成上述功能

 SessionConfiguration,用於第二步創建NSSession時設置工作模式和網絡設置:

工作模式分爲:

  • 一般模式(default):工作模式類似於原來的NSURLConnection,可以使用緩存的Cache,Cookie,鑑權。
  • 及時模式(ephemeral):不使用緩存的Cache,Cookie,鑑權。
  • 後臺模式(background):在後臺完成上傳下載,創建Configuration對象的時候需要給一個NSString的ID用於追蹤完成工作的Session是哪一個(後面會講到)。

網絡設置:參考NSURLConnection中的設置項。

  1. 創建一個NSURLSession,系統提供了兩個創建方法:

  • sessionWithConfiguration:
  • sessionWithConfiguration:delegate:delegateQueue:

    第一個粒度較低就是根據剛纔創建的Configuration創建一個Session,系統默認創建一個新的OperationQueue處理Session的消息。

    第二個粒度比較高,可以設定回調的delegate(注意這個回調delegate會被強引用),並且可以設定delegate在哪個OperationQueue回調,如果我們將其設置爲[NSOperationQueue mainQueue]就能在主線程進行回調非常的方便。

  2.創建一個NSURLRequest調用剛纔的NSURLSession對象提供的Task函數,創建一個NSURLSessionTask。

  根據職能不同Task有三種子類:

  • NSURLSessionUploadTask:上傳用的Task,傳完以後不會再下載返回結果;
  • NSURLSessionDownloadTask:下載用的Task;
  • NSURLSessionDataTask:可以上傳內容,上傳完成後再進行下載。

  得到的Task,調用resume開始工作。

  3. 如果是細粒度的Session調用,Session與Delegate會在指定的OperationQueue中進行交互,以咱們下載例子,交互過程的順序圖如下(假如不需要鑑權,即非HTTPS請求):

 

 

  5. 當不再需要連接調用Session的invalidateAndCancel直接關閉,或者調用finishTasksAndInvalidate等待當前Task結束後關閉。這時Delegate會收到URLSession:didBecomeInvalidWithError:這個事件。Delegate收到這個事件之後會被解引用。

  6. 如果是一個BackgroundSession,在Task執行的時候,用戶切到後臺,Session會和ApplicationDelegate做交互。當程序切到後臺後,在BackgroundSession中的Task還會繼續下載,這部分文檔敘述比較少,現在分三個場景分析下Session和Application的關係:

  • 當加入了多個Task,程序沒有切換到後臺。

  這種情況Task會按照NSURLSessionConfiguration的設置正常下載,不會和ApplicationDelegate有交互。

  • 當加入了多個Task,程序切到後臺,所有Task都完成下載。

  在切到後臺之後,Session的Delegate不會再收到,Task相關的消息,直到所有Task全都完成後,系統會調用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:回調,之後“彙報”下載工作,對於每一個後臺下載的Task調用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的話)和URLSession:task:didCompleteWithError:(成功或者失敗都會調用)。

  之後調用Session的Delegate回調URLSessionDidFinishEventsForBackgroundURLSession:。

  注意:在ApplicationDelegate被喚醒後,會有個參數ComplietionHandler,這個參數是個Block,這個參數要在後面Session的Delegate中didFinish的時候調用一下,如下:

@implementation APLAppDelegate

 

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier

  completionHandler:(void (^)())completionHandler

{

    BLog();

    /*

     Store the completion handler. The completion handler is invoked by the view controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been completed).

     */

      self.backgroundSessionCompletionHandler = completionHandler;

}

//……

@end

 

//Session的Delegate

@implementation APLViewController

 

- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session

{

    APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate];

    if (appDelegate.backgroundSessionCompletionHandler) {

        void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;

        appDelegate.backgroundSessionCompletionHandler = nil;

        completionHandler();

    }

 

    NSLog(@"All tasks are finished");

}

@end

 

  • 當加入了多個Task,程序切到後臺,下載完成了幾個Task,然後用戶又切換到前臺。(程序沒有退出)

  切到後臺之後,Session的Delegate仍然收不到消息。在下載完成幾個Task之後再切換到前臺,系統會先彙報已經下載完成的Task的情況,然後繼續下載沒有下載完成的Task,後面的過程同第一種情況。

  • 當加入了多個Task,程序切到後臺,幾個Task已經完成,但還有Task還沒有下載完的時候關掉強制退出程序,然後再進入程序的時候。(程序退出了)

  最後這個情況比較有意思,由於程序已經退出了,後面沒有下完Session就不在了後面的Task肯定是失敗了。但是已經下載成功的那些Task,新啓動的程序也沒有聽“彙報”的機會了。經過實驗發現,這個時候之前在NSURLSessionConfiguration設置的NSString類型的ID起作用了,當ID相同的時候,一旦生成Session對象並設置Delegate,馬上可以收到上一次關閉程序之前沒有彙報工作的Task的結束情況(成功或者失敗)。但是當ID不相同,這些情況就收不到了,因此爲了不讓自己的消息被別的應用程序收到,或者收到別的應用程序的消息,起見ID還是和程序的Bundle名稱綁定上比較好,至少保證唯一性

總結

  就像前面說的,在普通的應用場景下NSURLSession與NSURLConnection相比沒有什麼優勢,但是在程序切換到後臺之後Background的Session就顯得更加靈活了。

  另外,現在主流的網絡開發框架AFNetworking已經更新到了2.0(只支持iOS 6 / iOS 7),其中最重要的一個更新就是添加了NSURLSession相關的支持。雖然就我現在(2013.10.13)看到他們的源碼中,還沒有完全的支持後臺的Session(或者說沒有考慮全我上述的後臺情況),但是大家有興趣可以關注一下他們後續的更新情況。

參考資料:

蘋果官方文檔:

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/URLLoadingSystem/Articles/UsingNSURLSession.html#//apple_ref/doc/uid/TP40013509-SW1

注意:蘋果又開始不更新Xcode 中的文檔,然後悄悄在網上更新了,大家請關注相關文檔最後的更新時間,以最新的爲準

AFNetworking 2.0:

https://github.com/AFNetworking/AFNetworking/

發佈了84 篇原創文章 · 獲贊 121 · 訪問量 25萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章