你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 開發只懂 AFN ?搞定 NSURLSession 才是硬道理

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

編輯:IOS開發基礎

由於傲嬌的蘋果在 iOS9 之後已經放棄了 NSURLConnection,所以在現在的實際開發中,除了大家常見的 AFN 框架,一般使用的是 iOS7 之後推出的 NSURLSession,作為一名 iOS 開發人員,如果你只知道 AFN 框架來進行網絡請求,那就只能說是 too young too simple,sometimes naive。

2997426-97e16c332149b6ac.jpg

目錄

本來想創建一個目錄跳轉的,好像簡書不支持,只好作罷,有哪位大神知道怎麼在簡書支持目錄跳轉的,希望不吝賜教!
  1. NSURLSession 的優勢

  2. NSURLSessionTask 的子類

  3. NSURLSessionDataTask 發送 GET 請求

  4. NSURLSessionDataTask 發送 POST 請求

  5. NSURLSessionDataTask 設置代理發送請求

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

  7. NSURLSessionDataTask 簡單下載

  8. NSURLSessionDownloadTask 簡單下載

  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:@"此處為上傳文件的路徑"]



文章轉自 Mortal_Master的簡書
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved