iOS —— NNSURLSessionDataTask,nsurlsessiondatatask

來源:互聯網
上載者:User

iOS —— NNSURLSessionDataTask,nsurlsessiondatatask
一、基本簡介

1. NSURLSessionDataTask 是 NSURLSessionTask 的子類,是一個具體的 網路請求(task) 類,是網路請求中最常用的請求之一

通常,NSURLSessionDataTask 用來請求資料,可以用來下載資料資源,例如 JSON 資料,圖片資料等

 

2. 通常有以下幾種方法建立一個 data task

1)方法一 : 使用 NSURLSession 的執行個體方法

 

1 // @param url 待請求的 URL 地址2 // @param completionHandler 回調方法3 // @param data 從伺服器請求到的資料4 // @param response 回應標頭資訊5 // @param error 錯誤資訊6 - (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;

 

注意 :

該方法中會自動將 url 轉換為一個請求對象(NSURLRequest),並且該請求對象是 GET 請求方式

回調方法是在子線程中啟動並執行,所以如果在回調方法中重新整理 UI 必須回到主線程中

回調方法中有兩個參數 response / error,這兩個參數和 該訊息的接受者(即 NSURLSessionDataTask 對象)中的 response / error 是指同一個內容,即地址相同

使用該方法的缺點是不能監聽擷取資料的進度,因為只有當全部請求完資料後,才會調用這個方法,也就是說,data 中的資料是請求的全部資料

 

2)方法二 : 使用 NSURLSession 的執行個體方法

 

// @param request 請求對象- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request completionHandler:(void (^)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error))completionHandler;

 

方法二與方法一不同的地方在於 : 方法二可以手動佈建要求對象,這樣一來,就可以指定請求方式 GET/POST 中的一個;而方法一隻能是 GET 請求方式

剩餘的全部一樣

 

3)方法三 : 代理

方法一和方法二唯一的缺點就是不能監控請求進度,因為只有當請求完全部的資料後才會調用回調方法,如果想要監控請求進度,必須使用代理的方法

使用代理首先要自訂 NSURLSession 對象,使用下面的方法可以設定代理對象

 

// @param configuration 配置資訊對象// @param delegate 代理對象// @param queue 代理方法在哪個線程中運行,如果傳 nil 則會在子線程中運行代理方法+ (NSURLSession *)sessionWithConfiguration:(NSURLSessionConfiguration *)configuration delegate:(nullable id <NSURLSessionDelegate>)delegate delegateQueue:(nullable NSOperationQueue *)queue;

 

同時,必須遵守相關的協議

 

在使用下面的方法建立 data task

- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url;- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request;

這兩個方法的區別和方法一/方法二一樣,使用 url 則方法內部會自動將其轉換為一個 請求對象,並且是 GET 請求方式

 

二、範例程式碼

因為我是把所有的代碼寫到一個 demo 裡的,所以有些目前不需要的東西可以不必理會

1)GET/POST 請求

首先在 main.storyboard 中拖入一個 UINavigationController ,並設定 static cell,

 

然後拖入一個 UIViewController 並選中第一個 cell,即 NSURLSessionDataTask,將 cell 和 UIViewController 連線,選擇 push

在這個 UIViewController 中拖入一系列控制項,

 

右上方的 UIBarButtonItem 是跳轉到下一個介面的,不用管它

UIViewController 中的代碼如下

 

 1 #import "LHDataTaskViewController.h" 2  3 // GET 請求的 URL 4 static NSString * imageURL = @"http://120.25.226.186:32812/resources/images/minion_01.png"; 5  6 // POST 請求的 URL 7 static NSString * dataURL = @"http://api.hudong.com/iphonexml.do"; 8  9 @interface LHDataTaskViewController ()10 11 #pragma mark - 屬性12 @property (weak, nonatomic) IBOutlet UIImageView *showImageView;13 14 @property (nonatomic, strong) NSURLSession * session;15 @property (nonatomic, strong) NSURLSessionDataTask * dataTask;16 17 @end18 19 @implementation LHDataTaskViewController20 21 #pragma mark - ViewController 生命週期22 - (void)viewDidLoad {23     24     [super viewDidLoad];25     26     // 1. 初始化 NSURLSession 對象27     self.session = [NSURLSession sharedSession];28 29 }30 31 - (void)didReceiveMemoryWarning {32     33     [super didReceiveMemoryWarning];34 35 }

 

 

1. GET 請求

設定 "GET請求" 按鈕的 動作方法

 

 1 #pragma mark - button 動作方法 2 #pragma mark 發送 GET 請求擷取圖片資源 3 - (IBAction)GETButtonClick:(id)sender { 4      5     NSLog(@"dataTask的狀態 --- %li", _dataTask.state); 6      7     // 1. 初始化 NSURLSesionDataTask 對象 8     self.dataTask = [_session dataTaskWithURL:[NSURL URLWithString:imageURL] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { 9                 10         // 1). 定義 UIImage 對象,並用接受的資料(data)初始化11         UIImage * image = [UIImage imageWithData:data];12         13         // 2). 返回主線程重新整理UI14         dispatch_async(dispatch_get_main_queue(), ^{15             16             self.showImageView.image = image;17             18         });19         20         NSLog(@"dataTask的狀態 --- %li", _dataTask.state);21         22         // 此時,所有資料已經全部接受完畢,所以,已經接受的的資料和所要接受的總資料是相等的23         // 因為沒有發送資料,所以發送資料都為 024         NSLog(@"已接受到的資料量 --- %lli", _dataTask.countOfBytesReceived); // 4834725         NSLog(@"所要接受到的資料總量 --- %lli", _dataTask.countOfBytesExpectedToReceive); // 4834726         NSLog(@"已經發送的資料量 --- %lli", _dataTask.countOfBytesSent); // 027         NSLog(@"所要發送的資料總量 --- %lli", _dataTask.countOfBytesExpectedToSend); // 028         29     }];30     31     // 2. 發送請求,執行 task32     [_dataTask resume];33     34 }

 

其中,24行 —— 27行 中用到的屬性,在上一節已經介紹過

注意 : NSURLSessionTask 中所有的 task 都需要 resume 來開始

 

 

2. POST 請求

設定 "POST請求" 按鈕的動作方法

 

 1 - (IBAction)POSTButtonClick:(UIButton *)sender { 2      3     // 1. 建立請求對象(可變) 4     NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:dataURL]]; 5      6     // 2. 佈建要求方法為 POST 請求 7     request.HTTPMethod = @"POST"; 8      9     request.HTTPBody = [@"type=focus-c" dataUsingEncoding:NSUTF8StringEncoding];10     11     // 1. 初始化 NSURLSessionDataTask 對象12     self.dataTask = [_session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {13         14         NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);15         16     }];17     18     [_dataTask resume];19     20 }

 

2. 代理

使用代理的方法來進行網路請求,並且可以監控請求進度

現在 mian.storyboard 中拖入一個 UIViewController 並添加控制項,

 

本次請求的是一張圖片資料,請求完之後會將圖片顯示到螢幕上的 UIImageView,resume 按鈕是開始請求,pause 按鈕是暫停請求,cance 按鈕是取消請求,中間還有一個 UIProgressView,用於顯示請求的進度,並將這些控制項與插座變數關聯

 

UIViewController 中的代碼如下,該 ViewController 要遵守相關協議 <NSURLSessionDataDelegate>

 

 1 #import "LHDataTaskDownloadViewController.h" 2  3 // 待訪問的 URL 4 static NSString * imageURL = @"http://f12.topit.me/o129/10129120625790e866.jpg"; 5  6 @interface LHDataTaskDownloadViewController () <NSURLSessionDataDelegate> 7  8 #pragma mark - 屬性列表 9 #pragma mark 插座變數10 @property (weak, nonatomic) IBOutlet UIImageView *showImageView;11 @property (weak, nonatomic) IBOutlet UIProgressView *progressView;12 @property (weak, nonatomic) IBOutlet UIButton *resumeButton;13 @property (weak, nonatomic) IBOutlet UIButton *pauseButton;14 @property (weak, nonatomic) IBOutlet UIButton *cancelButton;15 16 #pragma mark 網路對象17 @property (nonatomic, strong) NSURLSession * session;18 @property (nonatomic, strong) NSURLSessionDataTask * dataTask;19 20 #pragma mark 用於接受資料的對象21 @property (nonatomic, strong) NSMutableData * data;22 23 @end24 25 @implementation LHDataTaskDownloadViewController26 27 - (void)viewDidLoad {28     29     [super viewDidLoad];30     31     // 1. 初始化 NSURLSession 對象,delegateQueue 為協議方法啟動並執行線程,傳 nil 則在子線程中運行32     self.session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:nil];33     34     // 2. 初始化 NSURLSessionDataTask 對象,預設為 GET35     self.dataTask = [_session dataTaskWithURL:[NSURL URLWithString:imageURL]];36     37     // 2. 將 cancelButton 和 pauseButton 按鈕設定為不可用38     _cancelButton.enabled = NO;39     40     _pauseButton.enabled = NO;41 42 }

 

 

開始按鈕的動作方法

 1 - (IBAction)resumeButtonClick:(id)sender { 2      3     // 1. 判斷當前的狀態,data task 預設為 暫停狀態 4     if (_dataTask.state == NSURLSessionTaskStateSuspended) { 5          6         _pauseButton.enabled = YES; 7          8         _cancelButton.enabled = YES; 9     10         // 1). 開始請求 task11         [_dataTask resume];12     13     }14     15 }

 

暫停按鈕的動作方法

 1 - (IBAction)pauseButtonClick:(id)sender { 2      3     // 1. 判斷 task 當前的狀態,如果處於正在接受資料的狀態,則暫停 4     if (_dataTask.state == NSURLSessionTaskStateRunning) { 5      6         [_dataTask suspend]; 7      8     } 9     10 }

 

取消按鈕的動作方法

 1 - (IBAction)cancelButtonClick:(id)sender { 2      3     // 1. 判斷 task 當前的狀態,如果處於正在接受資料的狀態或暫停狀態,則取消 4     if (_dataTask.state == NSURLSessionTaskStateRunning || _dataTask.state == NSURLSessionTaskStateSuspended) { 5      6         // 1). 取消 task 7         [_dataTask cancel]; 8          9         // 2). 設定滑動條的值10         _progressView.progress = 0;11         12         // 3). 建立對話方塊VC13         UIAlertController * alertVC = [UIAlertController alertControllerWithTitle:@"提示" message:@"該 Task 已經被取消" preferredStyle:UIAlertControllerStyleAlert];14         15         // 4). 顯示對話方塊VC16         [self presentViewController:alertVC animated:YES completion:nil];17         18         // 5). 建立動作按鈕19         UIAlertAction * cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {20            21             [self.navigationController popViewControllerAnimated:YES];22             23         }];24         25         // 6). 將動作按鈕添加到對話方塊VC26         [alertVC addAction:cancelAction];27     28     }29     30 }

 

協議方法

#pragma mark 接收到伺服器響應時調用,預設情況下不接受資料,所以要允許// @param session 當前的會話對象// @param dataTask 當前的 data task 對象// @param response 回應標頭對象// @param completionHandler 回調- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {        NSLog(@"%@", NSStringFromSelector(_cmd));    // 1. 初始化資料對象    self.data = [[NSMutableData alloc] init];        // 2. 允許接受資料,如果沒有寫這句,則後面代理的方法不會被執行    completionHandler(NSURLSessionResponseAllow);}

其中,NSURLSessionResponseDisposition 是一個枚舉

1 typedef NS_ENUM(NSInteger, NSURLSessionResponseDisposition) {2     NSURLSessionResponseCancel = 0,        // 取消接受資料,之後的代理方法不會被執行,相當於 [task cancel];          3     NSURLSessionResponseAllow = 1,         // 允許接受資料,之後的代理方法會被執行4     NSURLSessionResponseBecomeDownload = 2,// 使當前的 data task 變為 download task,當轉換為 download task 時,會將資料下載到 tmp 檔案中,不需要再接受資料了,並且必須調用下面的 iii) 方法,並且在該方法中可以什麼都不寫,但必須被調用           5     NSURLSessionResponseBecomeStream NS_ENUM_AVAILABLE(10_11, 9_0) = 3,// 使當前的 data task 變為 stream task6 } NS_ENUM_AVAILABLE(NSURLSESSION_AVAILABLE, 7_0);

 

 1 #pragma mark 接受到資料時調用,可能會調用多次 2 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { 3      4     NSLog(@"%@", NSStringFromSelector(_cmd)); 5      6     // 1. 拼接收到的資料 7     [self.data appendData:data]; 8      9     // 2. 回到主線程重新整理 UI10     dispatch_async(dispatch_get_main_queue(), ^{11        12         _progressView.progress = (float)_dataTask.countOfBytesReceived/_dataTask.countOfBytesExpectedToReceive;13         14     });15     16 }

 

 1 #pragma mark 請求結束或失敗時調用 2 - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 3  4     NSLog(@"%@", NSStringFromSelector(_cmd)); 5      6     UIImage * image = [UIImage imageWithData:_data]; 7      8     dispatch_async(dispatch_get_main_queue(), ^{ 9         10         NSLog(@"currentThread --- %@", [NSThread currentThread]);11         12         self.showImageView.image = image;13         14     });15 16 }

這個方法並不是 NSURLSessionTaskDelegate 協議中的方法,適合所有的 task

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.