USURLSession基本使用介紹

USURLSession基本使用介紹

在2013的WWDC上,蘋果推出了NSURLConnection的繼任者NSURLSession,并且在iOS9.0之后,以前使用的NSURLConnection將提示過期,推薦使用NSURLSession來替換NSURLConnection完成網路請求相關操作。與 NSURLConnection 一樣,NSURLSession 指的也不僅是同名類 NSURLSession,還包括一系列相互關聯的類。NSURLSession 包括了與之前相同的組件,NSURLRequest 與 NSURLCache,但是把 NSURLConnection 替換成了 NSURLSession、NSURLSessionConfiguration 以及 NSURLSessionTask 的 3 個子類:NSURLSessionDataTask,NSURLSessionUploadTask,NSURLSessionDownloadTask,這三個子類可以直接使用,每個任務都可以掛起(suspend),結束(cancel) 和 執行(resume),調用響應的函數即可
</br>
與 NSURLConnection 相比,NSURLsession 最直接的改進就是可以配置每個 session 的緩存,協議,cookie,以及證書策略(credential policy),甚至跨程序共享這些信息。這將允許程序和網絡基礎框架之間相互獨立,不會發生干擾。每個 NSURLSession 對象都由一個 NSURLSessionConfiguration 對象來進行初始化,后者指定了剛才提到的那些策略以及一些用來增強移動設備上性能的新選項。


1、NSURLSessionDataTask 獲取服務器上的數據,返回相關數據,獲取后直接處理
2、NSURLSessionUploadTask 創建一個上傳任務,在上傳時需要制定文件源或數據源,一般來說,對于一個上傳任務,也會收到服務的響應也會有相關數據返回,所以NSURLSessionUploadTask繼承于NSURLSessionDataTask
3、NSURLSessionDownloadTask 下載服務器上的數據,當任務結束的時候,他會帶回一個下載文件的一個臨時文件路徑,所以在下載大容量任務時,使用尤為方便。
每一個task都是可以取消,暫停或者恢復的。當一個 download task 取消時,可以通過選項來創建一個恢復數據(resume data),然后可以傳遞給下一次新創建的 download task,以便繼續之前的下載,這在斷點下載的時候尤為有用。

NSURLSession常用的類

1、NSURL:根據url生成的請求地址
2、NSURLRequest:封裝的一個請求,攜帶發送給服務器的全部數據,里面包含一個NSURL對象,請求方法,請求頭,請求體等等。
3、NSMutableURLRequest:這個是NSURLRequest的子類,通過名字我們可以看出這是一個可變的對象,我們可以在這里自定義設置發送的服務器的全部數據(超市等待時間、請求方法、請求體、請求頭)
4、NSURLResponse:服務的響應類,和NSURLRequest對象,包含服務返回的響應頭部數據
5、NSURLSessionConfiguration 用于配置會話的屬性,可以通過該類配置會話的工作模式:
+ (NSURLSessionConfiguration *)defaultSessionConfiguration; 工作模式類似于原來的NSURLConnection,可以使用緩存的Cache,Cookie,鑒權
+ (NSURLSessionConfiguration *)ephemeralSessionConfiguration; 不使用緩存的Cache,Cookie,鑒權。
+ (NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier; 創建一個后臺 session,后臺 session 不同于常規的,普通的 session,它甚至可以在應用程序掛起,退出或者崩潰的情況下運行上傳和下載任務,創建Configuration對象的時候需要給一個NSString的ID用于用于標記后臺的session。(稍后詳細描述)
6、NSURLSession:會話對象

NSURLSession的使用步驟

1、根據url創建一個NSURL對象
2、根據創建的NSURL創建一個NSURLRequest對象,創建請求對象(此對象內容全部都是默認值,如:請求方法默認是GET),如果想要自定數據則創建NSMutableURLRequest對象
3、創建會話對象NSURLSession,創建NSURLSession對象有三種方法:

1)+ (NSURLSession *)sharedSession; 返回一個默認的NSURLSession,使用共享的會話,該會話使用全局的Cache,Cookie和證書
2)+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration; 返回一個根據剛才創建的Configuration的NSURLSession對象,系統默認創建一個新的OperationQueue處理Session的消息
3)+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue; 返回一個根據剛才創建的Configuration的NSURLSession對象,可以設定回調的delegate(注意這個回調delegate會被強引用),并且可以設定delegate在哪個OperationQueue回調,如果我們將其設置為[NSOperationQueue mainQueue]就能在主線程進行回調非常的方便

4、使用創建好的NSURLSession對象和NSURLRequest對象創建一個NSURLSessionTask任務,NSURLSessionDataTask、NSURLSessionUploadTask 或者 NSURLSessionDownloadTask
5、調用resume開始工作
6、當不再需要連接調用Session的invalidateAndCancel直接關閉,或者調用finishTasksAndInvalidate等待當前Task結束后關閉。這時Delegate會收到URLSession:didBecomeInvalidWithError:這個事件。Delegate收到這個事件之后會被解引用。
</br>
和NSURLConnection一樣,NSURLSession也提供了兩種形式的使用,代理模式和非代理模式

非代理模式

每個task的構造方法都提供了一個–dataTaskWithRequest:completionHandler:的函數,類似NSURLConnection的sendAsynchronousRequest:queue:completionHandler:sendSynchronousRequest:returningResponse:error:模式,只是NSURLSession僅有異步版本。
例如,如果創建一個NSURLSessionDataTask任務:

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    
    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request
                                         completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         //接受的數據data、服務器響應response、錯誤代碼error
     }];

    //啟動task
    [task resume];
    //其它方法,如取消任務,暫停任務等
    //[task cancel];
    //[task suspend]

再者創建一個NSURLSessionUploadTask任務

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    NSData *data = ...; //上傳任務需要一個需要上傳的NSData對象或者一個本地文件路徑對應的NSURL
    
    NSURLSessionDataTask *uploadTask = [self.session uploadTaskWithRequest:request
                                                            fromData:data
                                                   completionHandler:
     ^(NSData *data, NSURLResponse *response, NSError *error) {
         //接受的數據data、服務器響應response、錯誤代碼error
     }];
     
    //啟動task
    [uploadTask resume];
    //其它方法,如取消任務,暫停任務等
    //[uploadTask cancel];
    //[uploadTask suspend];

我們再來看看NSURLSessionDownloadTask任務,下載任務的不同之處在于,NSURLSessionDownloadTask會一點一點的將下載數據寫入本地的臨時文件,回調block會帶回一個下載完成的臨時文件的地址,我們需要把文件從這個臨時地址移動到文件沙盒中保存起來使用。

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    
    NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request
                                                         completionHandler:
    ^(NSURL *location, NSURLResponse *response, NSError *error) {
        //文件臨時地址location,服務器響應response、錯誤代碼error
        //將臨時文件移動到app沙盒中
        NSString *documentsPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
        NSURL *documentsDirectoryURL = [NSURL fileURLWithPath:documentsPath];
        NSURL *newFileLocation = [documentsDirectoryURL URLByAppendingPathComponent:[[response URL] lastPathComponent]];
        [[NSFileManager defaultManager] copyItemAtURL:location toURL:newFileLocation error:nil];
    }];

    //啟動task
    [downloadTask resume];
    //其它方法,如取消任務,暫停任務等
    //[downloadTask cancel];
    //[downloadTask suspend];

代理模式

NSURLSession有幾個代理協議NSURLSessionDelegateNSURLSessionTaskDelegateNSURLSessionDataDelegateNSURLSessionDownloadDelegate這幾個協議個呈繼承關系,NSURLSessionTaskDelegate繼承NSURLSessionDelegate,NSURLSessionDataDelegate和NSURLSessionDownloadDelegate繼承自NSURLSessionTaskDelegate,實現不同的任務,就實現相應的協議。在這里我們以NSURLSessionDownloadDelegate協議為例:

    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    self.session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];
    NSString *imageURl = @"http://7xt5rm.com2.z0.glb.clouddn.com/picjumbo.com_download.jpg";
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:imageURl]];
    
    //創建下載task
    NSURLSessionDownloadTask *downloadTask = [self.session downloadTaskWithRequest:request];
    
    //啟動task
    [downloadTask resume];
    //其它方法,如取消任務,暫停任務等
    //[downloadTask cancel];
    //[downloadTask suspend];

代理方法,主要有這么幾個:

//當接收到服務器響應的時候調用
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
                                 didReceiveResponse:(NSURLResponse *)response
                                  completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler;

//下載完成之后調用該方法
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                              didFinishDownloadingToURL:(NSURL *)location;

//當接收到下載數據的時候調用,可以在該方法中監聽文件下載的進度該方法會被調用多次
//totalBytesWritten:已經寫入到文件中的數據大小
//totalBytesExpectedToWrite:目前文件的總大小
//bytesWritten:本次下載的文件數據大小
//可以在此函數中計算下載進度
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                           didWriteData:(int64_t)bytesWritten
                                      totalBytesWritten:(int64_t)totalBytesWritten
                              totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
//恢復下載的時候調用該方法
//fileOffset:恢復之后,要從文件的什么地方開發下載
//expectedTotalBytes:該文件數據的總大小
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
                                      didResumeAtOffset:(int64_t)fileOffset
                                     expectedTotalBytes:(int64_t)expectedTotalBytes;

//當請求完成之后調用該方法
//不論是請求成功還是請求失敗都調用該方法,如果請求失敗,那么error對象有值,否則那么error對象為空
//所有方法之中最后調用
-(void)URLSession:(nonnull NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error

和NSURLConnection一樣我們這里也介紹一下斷點下載的相關代碼

第一種:每一個task都是有三種狀態掛起、執行和取消,所以我們可以在暫停時刻掛起任務,重新下載時執行任務即可
        if (downloadTask.state == NSURLSessionTaskStateSuspended) {
            [downloadTask resume];
        } else {
            [downloadTask suspend];
        }
     但是很多時候不是使用這種方法,不知有哪里不妥。。
第二種:取消的任務的時候保存已下載文件的信息,在恢復下載時,傳入此信息。
    //取消下載
    [downloadTask cancelByProducingResumeData:^(NSData * __nullable resumeData) {
        self.resumeData = resumeData;
    }];
    //恢復下載
    downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
    [downloadTask resume];
    比較常用的是這一種。。

后臺下載

前面講到我們可以通過設置NSURLSessionConfiguration的屬性BackgroundSession來實現后臺下載,在Task執行的時候,用戶切到后臺,Session會和ApplicationDelegate做交互。當程序切到后臺后,在BackgroundSession中的Task還會繼續下載。
在切到后臺之后,Session的Delegate不會再收到Task相關的消息,直到所有Task全都完成后,系統會調用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:回調,之后“匯報”下載工作,對于每一個后臺下載的Task調用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:(成功的話)和URLSession:task:didCompleteWithError:(成功或者失敗都會調用)之后調用Session的Delegate回調URLSessionDidFinishEventsForBackgroundURLSession:

看一下代碼:
在AppDelegate.m中,加入后臺處理函數

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{
    
    self.backgroundTransferCompletionHandler = completionHandler;
    
}

實現delegate的-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session方法

// 后臺傳輸完成,處理URLSession完成事件
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
    
    //檢查一下是否所有的下載任務都已經完成
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
        if ([uploadTasks count] == 0) {
            if (appDelegate.backgroundTransferCompletionHandler != nil) {
                //在ApplicationDelegate被喚醒后,會有個參數ComplietionHandler,這個參數是個Block,這個參數要在后面Session的Delegate中didFinish的時候調用一下
                
                void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;
                appDelegate.backgroundTransferCompletionHandler = nil;
                completionHandler();
            }
        }    
        
    }];
    //執行其他操作
    NSLog(@"All tasks are finished"); 
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • iOS開發系列--網絡開發 概覽 大部分應用程序都或多或少會牽扯到網絡開發,例如說新浪微博、微信等,這些應用本身可...
    lichengjin閱讀 3,721評論 2 7
  • NSURLSession 使用步驟使用NSURLSession對象創建Task,然后執行Task -(void)g...
    BEYOND黃閱讀 930評論 0 0
  • 在蘋果徹底棄用NSURLConnection之后自己總結的一個網上的內容,加上自己寫的小Demo,很多都是借鑒網絡...
    付寒宇閱讀 4,316評論 2 13
  • 直接將view添加到Window上面,[[UIApplication sharedApplication].del...
    AnderQZ閱讀 208評論 0 0
  • 自習室告一段落后……………………曖昧 是一種微妙的感覺有所保留又有所突破我喜歡這種感覺我想永遠保持這種感覺但世間之...
    純真閱讀 247評論 0 1