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

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

發佈於:2013-11-06 10:53閱讀數:10274

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

NSURLSession是iOS7中新的網絡接口,它與咱們熟悉的NSURLConnection是並列的。在程序在前臺時,NSURLSession與NSURLConnection可以互爲替代工作。注意,如果用戶強制將程序關閉,NSURLSession會斷掉。
 
NSURLSession提供的功能:
1.通過URL將數據下載到內存
2.通過URL將數據下載到文件系統
3.將數據上傳到指定URL
4.在後臺完成上述功能
 
工作流程
如果我們需要利用NSURLSession進行數據傳輸我們需要:
1.創建一個NSURLSessionConfiguration,用於第二步創建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請求):
4.當不再需要連接調用Session的invalidateAndCancel直接關閉,或者調用finishTasksAndInvalidate等待當前Task結束後關閉。這時Delegate會收到URLSession:didBecomeInvalidWithError:這個事件。Delegate收到這個事件之後會被解引用。
 
5.如果是一個BackgroundSession,在Task執行的時候,用戶切到後臺,Session會和ApplicationDelegate做交互。當程序切到後臺後,在BackgroundSession中的Task還會繼續下載,這部分文檔敘述比較少,現在分三個場景分析下Session和Application的關係:
 
1)當加入了多個Task,程序沒有切換到後臺。
這種情況Task會按照NSURLSessionConfiguration的設置正常下載,不會和ApplicationDelegate有交互。
 
2)當加入了多個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的時候調用一下,如下:
  1. @implementation APLAppDelegate 
  2.  
  3.   
  4.  
  5. - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier 
  6.  
  7.   completionHandler:(void (^)())completionHandler 
  8.  
  9.  
  10.     BLog(); 
  11.  
  12.     /* 
  13.  
  14.      Store the completion handler. The completion handler is invoked by the view controller's checkForAllDownloadsHavingCompleted method (if all the download tasks have been completed). 
  15.  
  16.      */ 
  17.  
  18.       self.backgroundSessionCompletionHandler = completionHandler; 
  19.  
  20.  
  21. //…… 
  22.  
  23. @end 
  24.  
  25.   
  26.  
  27. //Session的Delegate 
  28.  
  29. @implementation APLViewController 
  30.  
  31.   
  32.  
  33. - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session 
  34.  
  35.  
  36.     APLAppDelegate *appDelegate = (APLAppDelegate *)[[UIApplication sharedApplication] delegate]; 
  37.  
  38.     if (appDelegate.backgroundSessionCompletionHandler) { 
  39.  
  40.         void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler; 
  41.  
  42.         appDelegate.backgroundSessionCompletionHandler = nil; 
  43.  
  44.         completionHandler(); 
  45.  
  46.     } 
  47.  
  48.   
  49.  
  50.     NSLog(@"All tasks are finished"); 
  51.  
  52.  
  53. @end 
 
3)當加入了多個Task,程序切到後臺,下載完成了幾個Task,然後用戶又切換到前臺。(程序沒有退出)
  
切到後臺之後,Session的Delegate仍然收不到消息。在下載完成幾個Task之後再切換到前臺,系統會先彙報已經下載完成的Task的情況,然後繼續下載沒有下載完成的Task,後面的過程同第一種情況。
 
4)當加入了多個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(或者說沒有考慮全我上述的後臺情況),但是大家有興趣可以關注一下他們後續的更新情況。
 
 
參考資料:
蘋果官方文檔:Using NSURLSession
注意:蘋果又開始不更新Xcode 中的文檔,然後悄悄在網上更新了,大家請關注相關文檔最後的更新時間,以最新的爲準
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章