iOS網絡--NSURLSession基本使用(1)

一、NSURLSession

NSURLSession是蘋果對網絡會話的封裝,可以完全替代原來的NSURLConnection。相比於NSURLConnection,NSURLSession具備以下優勢:

  1. 支持http2.0協議
  2. 在處理下載任務的時候可以將下載內容寫入磁盤(NSURLSessionDownloadTask)
  3. 支持後臺下載/上傳
  4. 同一個NSURLSession可以發送多個請求,只需要建立一次連接
  5. 提供了全局的session(單例)與一些內置的配置,使用方便
  6. 下載的處理策略是多線程異步下載,效率高。

二、NSURLSessionTask

NSURLSession只是提供了一個會話,真正的下載任務是由NSURLSessionTask進行管理的。

                                 

上面的圖是NSURLSessionTask的類結構圖,我們常用的就是NSURLSessionTask的兩個直接子類:NSURLSessionDataTask和NSURLSessionDownloadTask。前者下載,上傳任務都可以勝任,後者主要是對下載任務的管理,就是說後者中有對下載任務的細化管理,比如下載進度等。NSURLSessionDataTask還有一個直接子類--NSURLSessionUploadTask,這個類又將上傳任務做了一個細化。個人認爲這個類應該和NSURLSessionDownloadTask是同一層次的。

三、NSURLSession的使用

1.下載

使用NSURLSession下載資源有兩種方式,一種是通過URL下載,一種是通過請求來下載。

     (1)、通過URL下載資源

通過URL來下載資源,對於下載數據回調的方式又有兩種方式,一種是block的方式,另一種就是代理的方式

               1.通過block方式回調下載數據

//1.準備URL
    NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.創建一個session 會話
NSURLSession * session = [NSURLSession sharedSession];
//3.通過session實例創建一個基於URL的任務
NSURLSessionDataTask * task = [session dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
       NSLog(@"%@",[UIImage imageWithData:data]);
}];
//4.啓動下載任務
[task resume];

特別注意最後需要手動啓動下載任務。PS:這種block的回調方式沒有進度。

                2.通過代理的方式來回調下載數據

//1.準備URL
    NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.創建會話
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//3.創建下載任務
NSURLSessionDataTask * task  = [session dataTaskWithURL:url];
//4.啓動下載任務
[task resume];

由於需要通過代理來回調下載數據,所以我們需要對session進行配置,NSURLSessionConfigration就是用來配置session的(嗯,英文好一點的小夥伴都看出來了😉),我們使用它的類方法來創建一個配置,這個配置是默認的session配置(一般都用這個配置),然後通過這個配置來創建一個session,這裏我們看到了代理--->參數delegate,這意味着我們需要在這個類中實現它的代理方法,這個等一會兒在說,後面的參數:delegateQueue表示代理在哪個隊列中工作,這和session本身工作所在的線程不一樣,詳見這一篇博客:https://www.cnblogs.com/xiaowuqing/p/7512413.html

設置了delegate就需要服從相關的代理和實現代理的方法來實現回調數據給我們。由於這裏我們創建的是NSURLSessionDataTask,所以我們服從的代理是NSURLSessionDataDelegate。這個代理下我們需要實現的方法是(常用的幾個方法):

-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    //接收相應的數據
    //和URLConnection的不同點在於接收到響應信息之後是否需要繼續下載,必須自己配置
    //告訴服務器繼續傳遞數據
    completionHandler(NSURLSessionResponseAllow);
    
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
    //這裏接收到真正的數據
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    //這裏的error如果爲空,則說明數據接收完畢
}

第一個方法就是收到服務器的相應頭時回調的方法,我們一般在這個方法中計算所請求數據的總大小。需要特別注意的是這個方法也會回調一個block:completionHandler() 通過給這個block回調一個枚舉值來告訴服務器還需不需要繼續傳遞數據。

第二個方法就是回調的數據真正來的方法。

第三個方法就是回調數據結束了。

(3)、通過request來下載資源

        1.通過block的方式

//1.初始化URL
NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.準備請求
NSURLRequest * request = [NSURLRequest requestWithURL:url];
//3.準備session
NSURLSession * session = [NSURLSession sharedSession];
//4.創建下載任務
NSURLSessionDataTask * task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    NSLog(@"%@",[UIImage imageWithData:data]);
}];
//5.啓動下載任務
[task resume];

這裏我們創建的request是默認的request,也就是get請求。與上面通過url來下載數據的不同之處在於,多了一步創建request的過程。

         2.通過delegate的方式

//1.初始化URL
NSURL * url = [NSURL URLWithString:@"http://pic32.nipic.com/20130823/13339320_183302468194_2.jpg"];
//2.準備請求
NSURLRequest * request = [NSURLRequest requestWithURL:url];
//3.創建session
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
//4.創建下載任務
NSURLSessionDataTask * task = [session dataTaskWithRequest:request];
//5.開始下載
[task resume];

然後服從代理,實現代理的方法

-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    //接收相應的數據
    //和URLConnection的不同點在於接收到響應信息之後是否需要繼續下載,必須自己配置
    //告訴服務器繼續傳遞數據
    completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
    
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    NSLog(@"%@",[UIImage imageWithData:self.mData]);
}

2、使用NSURLSessionDownLoadTask下載

上面的下載方式是直接將數據下載到內存中,這樣對於小型的數據來說內存是可以接受的,但是對於視頻或者大一點的圖片將其直接下載到內存確實欠妥。所以當我們需要下載文件時,最好使用NSURLDownloadTask來處理,這個類還能夠將下載的數據寫入磁盤中。

//這裏的self.task是NSURLSessionDownLoadTask
NSURL * url = [NSURL URLWithString:@"http://pic15.nipic.com/20110628/1369025_192645024000_2.jpg"];
NSURLSessionConfiguration * config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession * session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:[NSOperationQueue mainQueue]];
self.task = [session downloadTaskWithURL:url];
[_task resume];

這裏我們使用的是代理回調數據的方式,注意創建task用的是 downloadTaskWithURL 的方式,這個方法返回一個NSURLSessionDownLoadTask的對象。

遵守的協議:NSURLSessionDownloadDelegate

實現的代理方法:

-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
    //將默認下載的數據從location中拷貝或者移動到自己的路徑下面
    //當這個方法執行完畢這個臨時文件就會被立刻銷燬
    //所以要拷貝
    //獲取保存的文件的路徑
    NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingPathComponent:@"1.jpg"];
    //將location對應的文件拷貝到指定的路徑中
    [[NSFileManager defaultManager]moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:nil];
}
//獲取每次下載的進度
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
    //注意這裏是浮點的要乘以1.0
    CGFloat pregress = totalBytesWritten*1.0/totalBytesExpectedToWrite;
   
}
//下載完畢
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    NSLog(@"%@",error.userInfo);
}

第一個方法是當將下載內容寫到對應的一個locationURL下面時調用的方法,這個方法中我們需要將這個下載到location的內容移動到自己的目錄下,因爲這個方法一跑完就會將下載到location的內容刪除。

第二個方法可以獲取下載過程中的進度

bytesWritten:表示此次下載的字節數

totalBytesWritten:表示加上此次目前一共下載的字節數

totalBytesExpectedToWrite:表示一共需要下載多少字節。

所以進度就可以算出來啦~

最後一個方法就不用贅述了吧🙂

 

 

PS:對於上傳任務,由於上傳採用的方式一般是POST,而將數據寫入到POST的請求體中是一件比較複雜而又細緻的工作,所以我們一般都是使用的AFNetWorking這個框架~

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