開發只懂 AFN ?搞定 NSURLSession 纔是硬道理

因爲傲嬌的蘋果在 iOS9 以後已經放棄了 NSURLConnection,因此在如今的實際開發中,除了你們常見的 AFN 框架,通常使用的是 iOS7 以後推出的 NSURLSession,做爲一名 iOS 開發人員,若是你只知道 AFN 框架來進行網絡請求,那就只能說是 too young too simple,sometimes naive。服務器

目錄

原本想建立一個目錄跳轉的,好像簡書不支持,只好做罷,有哪位大神知道怎麼在簡書支持目錄跳轉的,但願不吝賜教!網絡

  1. NSURLSession 的優點session

  2. NSURLSessionTask 的子類多線程

  3. NSURLSessionDataTask 發送 GET 請求app

  4. NSURLSessionDataTask 發送 POST 請求框架

  5. NSURLSessionDataTask 設置代理髮送請求異步

  6. 設置代理以後的強引用問題async

  7. NSURLSessionDataTask 簡單下載url

  8. NSURLSessionDownloadTask 簡單下載spa

  9. dataTask 和 downloadTask 下載對比

  10. 寫在最後

 

NSURLSession 的優點

  • NSURLSession 支持 http2.0 協議

  • 在處理下載任務的時候能夠直接把數據下載到磁盤

  • 支持後臺下載|上傳

  • 同一個 session 發送多個請求,只須要創建一次鏈接(複用了TCP)

  • 提供了全局的 session 而且能夠統一配置,使用更加方便

  • 下載的時候是多線程異步處理,效率更高

 

NSURLSessionTask 的子類

  • NSURLSessionTask 是一個抽象類,若是要使用那麼只能使用它的子類

  • NSURLSessionTask 有兩個子類

    • NSURLSessionDataTask,能夠用來處理通常的網絡請求,如 GET | POST 請求等

      • NSURLSessionDataTask 有一個子類爲 NSURLSessionUploadTask,用於處理上傳請求的時候有優點

    • NSURLSessionDownloadTask,主要用於處理下載請求,有很大的優點

      NSURLSession 的子類

    • 2997426-7e7b79022303d11e.png

 

NSURLSessionDataTask 發送 GET 請求


發送 GET 請求的步驟很是簡單,只須要兩步就能夠完成:

  1. 使用 NSURLSession 對象建立 Task

  2. 執行 Task

    //肯定請求路徑
     NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login?username=520&pwd=520&type=JSON"];
     //建立 NSURLSession 對象
     NSURLSession *session = [NSURLSession sharedSession];
    
     /**
      根據對象建立 Task 請求
    
      url  方法內部會自動將 URL 包裝成一個請求對象(默認是 GET 請求)
      completionHandler  完成以後的回調(成功或失敗)
    
      param data     返回的數據(響應體)
      param response 響應頭
      param error    錯誤信息
      */
     NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:
                 ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    
         //解析服務器返回的數據
         NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
         //默認在子線程中解析數據
         NSLog(@"%@", [NSThread currentThread]);
     }];
     //發送請求(執行Task)
     [dataTask resume];

 

NSURLSessionDataTask 發送 POST 請求


發送 POST 請求的步驟與發送 GET 請求同樣:

  1. 使用 NSURLSession 對象建立 Task

  2. 執行 Task

    //肯定請求路徑
     NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
     //建立可變請求對象
     NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
     //修改請求方法
     requestM.HTTPMethod = @"POST";
     //設置請求體
     requestM.HTTPBody = [@"username=520&pwd=520&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
     //建立會話對象
     NSURLSession *session = [NSURLSession sharedSession];
     //建立請求 Task
     NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM completionHandler:
                 ^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    
         //解析返回的數據
         NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
     }];
     //發送請求
     [dataTask resume];

 

NSURLSessionDataTask 設置代理髮送請求

  1. 建立 NSURLSession 對象設置代理

  2. 使用 NSURLSession 對象建立 Task

  3. 執行 Task

    //肯定請求路徑
     NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
     //建立可變請求對象
     NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
     //設置請求方法
     requestM.HTTPMethod = @"POST";
     //設置請求體
     requestM.HTTPBody = [@"username=520&pwd=520&type=JSON" dataUsingEncoding:NSUTF8StringEncoding];
     //建立會話對象,設置代理
     /**
      第一個參數:配置信息
      第二個參數:設置代理
      第三個參數:隊列,若是該參數傳遞nil 那麼默認在子線程中執行
      */
     NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]
                                  delegate:self delegateQueue:nil];
     //建立請求 Task
     NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:requestM];
     //發送請求
     [dataTask resume];
  4. 遵照協議,實現代理方法(經常使用的有三種代理方法)

    -(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask 
    didReceiveResponse:(nonnull NSURLResponse *)response 
    completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler {
         //子線程中執行
         NSLog(@"接收到服務器響應的時候調用 -- %@", [NSThread currentThread]);
    
         self.dataM = [NSMutableData data];
         //默認狀況下不接收數據
         //必須告訴系統是否接收服務器返回的數據
         completionHandler(NSURLSessionResponseAllow);
    }
    -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
    
         NSLog(@"接受到服務器返回數據的時候調用,可能被調用屢次");
         //拼接服務器返回的數據
         [self.dataM appendData:data];
    }
    -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    
         NSLog(@"請求完成或者是失敗的時候調用");
         //解析服務器返回數據
         NSLog(@"%@", [[NSString alloc] initWithData:self.dataM encoding:NSUTF8StringEncoding]);
    }

 

設置代理以後的強引用問題

  • NSURLSession 對象在使用的時候,若是設置了代理,那麼 session 會對代理對象保持一個強引用,在合適的時候應該主動進行釋放

  • 能夠在控制器調用 viewDidDisappear 方法的時候來進行處理,能夠經過調用 invalidateAndCancel 方法或者是 finishTasksAndInvalidate 方法來釋放對代理對象的強引用

    • invalidateAndCancel 方法直接取消請求而後釋放代理對象

    • finishTasksAndInvalidate 方法等請求完成以後釋放代理對象。

      [self.session finishTasksAndInvalidate];

 

NSURLSessionDataTask 簡單下載


在前面請求數據的時候就至關於一個簡單的下載過程,NSURLSessionDataTask 下載文件具體的步驟與上相似:

  1. 使用 NSURLSession 對象建立一個 Task 請求

  2. 執行請求

    [[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:
         @"http://120.25.226.186:32812/resources/images/minion_01.png"] 
         completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    
         //解析數據
         UIImage *image = [UIImage imageWithData:data];
         //回到主線程設置圖片
         dispatch_async(dispatch_get_main_queue(), ^{
             self.imageView.image = image;
         });
    
     }] resume];

 

NSURLSessionDownloadTask 簡單下載

  1. 使用 NSURLSession 對象建立下載請求

  2. 在下載請求中移動文件到指定位置

  3. 執行請求

    //肯定請求路徑
     NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
     //建立請求對象
     NSURLRequest *request = [NSURLRequest requestWithURL:url];
     //建立會話對象
     NSURLSession *session = [NSURLSession sharedSession];
     //建立會話請求
     //優勢:該方法內部已經完成了邊接收數據邊寫沙盒的操做,解決了內存飆升的問題
     NSURLSessionDownloadTask *downTask = [session downloadTaskWithRequest:request 
         completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
    
         //默認存儲到臨時文件夾 tmp 中,須要剪切文件到 cache
         NSLog(@"%@", location);//目標位置
         NSString *fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]  
                             stringByAppendingPathComponent:response.suggestedFilename];
    
         /**
          fileURLWithPath:有協議頭
          URLWithString:無協議頭
          */
         [[NSFileManager defaultManager] moveItemAtURL:location toURL:[NSURL fileURLWithPath:fullPath] error:nil];
    
     }];
     //發送請求
     [downTask resume];

    以上方法沒法監聽下載進度,如要獲取下載進度,可使用代理的方式進行下載。

 

dataTask 和 downloadTask 下載對比

  • NSURLSessionDataTask

    • 下載文件能夠實現離線斷點下載,可是代碼相對複雜

  • NSURLSessionDownloadTask

    • 下載文件能夠實現斷點下載,但不能離線斷點下載

    • 內部已經完成了邊接收數據邊寫入沙盒的操做

    • 解決了下載大文件時的內存飆升問題

 

寫在最後

關於使用 NSURLSession 進行上傳文件操做,我只想說真的很麻煩,建議你們時間充沛且有興趣的能夠研究一下,若是不想研究也是能夠的,繼續使用咱們偉大的 AFN 框架就好。至於 AFN 框架的使用,這裏就不贅述了,後期若是有時間會更新一些經常使用的 AFN 使用方法,敬請期待。

附:使用 NSURLSession 上傳文件主要步驟及注意點

  • 主要步驟:

    1. 肯定上傳請求的路徑( NSURL )

    2. 建立可變的請求對象( NSMutableURLRequest )

    3. 修改請求方法爲 POST

    4. 設置請求頭信息(告知服務器端這是一個文件上傳請求)

    5. 按照固定的格式拼接要上傳的文件等參數

    6. 根據請求對象建立會話對象( NSURLSession 對象)

    7. 根據 session 對象來建立一個 uploadTask 上傳請求任務

    8. 執行該上傳請求任務(調用 resume 方法)

    9. 獲得服務器返回的數據,解析數據(上傳成功 | 上傳失敗)

  • 注意點:

    1. 建立可變的請求對象,由於須要修改請求方法爲 POST,設置請求頭信息

    2. 設置請求頭這個步驟可能會被遺漏

    3. 要處理上傳參數的時候,必定要按照固定的格式來進行拼接

    4. 須要採用合適的方法來得到上傳文件的二進制數據類型( MIMEType,獲取方式以下)

      • 點擊這裏搜索

      • 對着該文件發送一個網絡請求,接收到該請求響應的時候,能夠經過響應頭信息中的 MIMEType 屬性獲得

      • 使用通用的二進制數據類型表示任意的二進制數據  application/octet-stream

      • 調用 C 語言的 API 來獲取

        [self mimeTypeForFileAtPath:@"此處爲上傳文件的路徑"]

 

原文:http://www.jianshu.com/p/b0ddadd34037

相關文章
相關標籤/搜索