iOS開發網絡篇—NSURLConnection基本使用
一、NSURLConnection的常用類
(1)NSURL:請求地址
(2)NSURLRequest:封裝一個請求,保存發給服務器的全部數據,包括一個NSURL對象,請求方法、請求頭、請求體....
(3)NSMutableURLRequest:NSURLRequest的子類
(4)NSURLConnection:負責發送請求,建立客戶端和服務器的連接。發送NSURLRequest的數據給服務器,並收集來自服務器的響應數據
二、NSURLConnection的使用 1.簡單說明使用NSURLConnection發送請求的步驟很簡單
(1)創建一個NSURL對象,設置請求路徑(設置請求路徑)
(2)傳入NSURL創建一個NSURLRequest對象,設置請求頭和請求體(創建請求對象)
(3)使用NSURLConnection發送NSURLRequest(發送請求)
2.代碼示例
(1)發送請求的三個步驟:
1.設置請求路徑 2.創建請求對象 3.發送請求 3.1發送同步請求(一直在等待服務器返回數據,這行代碼會卡住,如果服務器,沒有返回數據,那麼在主線程UI會卡住不能繼續執行操作)有返回值 3.2發送異步請求:沒有返回值 說明:任何NSURLRequest默認都是get請求。 (2)發送同步請求代碼示例:1 // 2 // YYViewController.m 3 // 01-NSURLConnection的使用(GET) 4 // 5 // Created by apple on 14-6-28. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "MBProgressHUD+MJ.h" 11 12 @interface YYViewController () 13 @property (weak, nonatomic) IBOutlet UITextField *username; 14 @property (weak, nonatomic) IBOutlet UITextField *pwd; 15 - (IBAction)login; 16 17 @end 18 19 @implementation YYViewController 20 21 - (IBAction)login { 22 // 1.提前的表單驗證 23 if (self.username.text.length==0) { 24 [MBProgressHUD showError:@"請輸入用戶名"]; 25 return; 26 } 27 if (self.pwd.text.length==0) { 28 [MBProgressHUD showError:@"請輸入密碼"]; 29 return; 30 } 31 // 2.發送請求給服務器(帶上賬號和密碼) 32 //添加一個遮罩,禁止用戶操作 33 // [MBProgressHUD showMessage:@"正在努力加載中...."]; 34 // GET請求:請求行\請求頭\請求體 35 // 36 // 1.設置請求路徑 37 NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/login?username=%@&pwd=%@",self.username.text,self.pwd.text]; 38 NSURL *url=[NSURL URLWithString:urlStr]; 39 // 2.創建請求對象 40 NSURLRequest *request=[NSURLRequest requestWithURL:url]; 41 // 3.發送請求 42 //發送同步請求,在主線程執行 43 NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 44 //(一直在等待服務器返回數據,這行代碼會卡住,如果服務器沒有返回數據,那麼在主線程UI會卡住不能繼續執行操作) 45 NSLog(@"--%d--",data.length); 46 } 47 @end
模擬器情況:
打印服務器返回的信息:
補充說明: 1.提前的表單驗證 2.發送請求給服務器(帶上賬號和密碼) GET請求:請求行\請求頭\請求體 注意:GET請求中不存在請求體,因為所有的信息都寫在URL裡面。在IOS裡面,請求行和請求頭都不用寫。 (3)發送異步請求 發送異步請求有兩種方式: 1)使用block回調 2)代理 A.使用block回調方法發送異步請求 使用block回調代碼示例:1 // 2 // YYViewController.m 3 // 01-NSURLConnection的使用(GET) 4 // 5 // Created by apple on 14-6-28. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "MBProgressHUD+MJ.h" 11 12 @interface () 13 @property (weak, nonatomic) IBOutlet UITextField *username; 14 @property (weak, nonatomic) IBOutlet UITextField *pwd; 15 - (IBAction)login; 16 17 @end 18 19 @implementation YYViewController 20 21 - (IBAction)login { 22 // 1.提前的表單驗證 23 if (self.username.text.length==0) { 24 [MBProgressHUD showError:@"請輸入用戶名"]; 25 return; 26 } 27 if (self.pwd.text.length==0) { 28 [MBProgressHUD showError:@"請輸入密碼"]; 29 return; 30 } 31 // 2.發送請求給服務器(帶上賬號和密碼) 32 //添加一個遮罩,禁止用戶操作 33 [MBProgressHUD showMessage:@"正在努力加載中...."]; 34 35 // 36 // 1.設置請求路徑 37 NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/login?username=%@&pwd=%@",self.username.text,self.pwd.text]; 38 NSURL *url=[NSURL URLWithString:urlStr]; 39 40 // 2.創建請求對象 41 NSURLRequest *request=[NSURLRequest requestWithURL:url]; 42 43 // 3.發送請求 44 //3.1發送同步請求,在主線程執行 45 // NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil]; 46 //(一直在等待服務器返回數據,這行代碼會卡住,如果服務器沒有返回數據,那麼在主線程UI會卡住不能繼續執行操作) 47 48 //3.1發送異步請求 49 //創建一個隊列(默認添加到該隊列中的任務異步執行) 50 // NSOperationQueue *queue=[[NSOperationQueue alloc]init]; 51 //獲取一個主隊列 52 NSOperationQueue *queue=[NSOperationQueue mainQueue]; 53 [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 54 NSLog(@"--block回調數據--%@---%d", [NSThread currentThread],data.length); 55 //隱藏HUD,刷新UI的操作一定要放在主線程執行 56 [MBProgressHUD hideHUD]; 57 58 //解析data 59 /* 60 {"success":"登錄成功"} 61 {"error":"用戶名不存在"} 62 {"error":"密碼不正確"} 63 */ 64 NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; 65 NSLog(@"%@",dict); 66 67 //判斷後,在界面提示登錄信息 68 NSString *error=dict[@"error"]; 69 if (error) { 70 [MBProgressHUD showError:error]; 71 }else 72 { 73 NSString *success=dict[@"success"]; 74 [MBProgressHUD showSuccess:success]; 75 } 76 }]; 77 NSLog(@"請求發送完畢"); 78 } 79 @end
模擬器情況(注意這裡使用了第三方框架):
打印查看:
代碼說明: block代碼段:當服務器有返回數據的時候調用會開一條新的線程去發送請求,主線程繼續往下走,當拿到服務器的返回數據的數據的時候再回調block,執行block代碼段。這種情況不會卡住主線程。 隊列的作用:決定這個block操作放在哪個線程執行? 刷新UI界面的操作應該放在主線程執行,不能放在子線程,在子線程處理UI相關操作會出現一些莫名的問題。 提示: (1)創建一個操作,放在NSOperation隊列中執行,默認是異步執行的。 (2)mainqueue 返回一個和主線程相關的隊列,即主隊列。 新的問題:如果向服務器發送請求,卻並沒有拿到數據,那麼程序會崩潰(data不能為空) 改進代碼:1 NSOperationQueue *queue=[NSOperationQueue mainQueue]; 2 [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { 3 //當請求結束的時候調用(有兩種結果,一個是成功拿到數據,也可能沒有拿到數據,請求失敗) 4 NSLog(@"--block回調數據--%@---%d", [NSThread currentThread],data.length); 5 //隱藏HUD,刷新UI的操作一定要放在主線程執行 6 [MBProgressHUD hideHUD]; 7 8 //解析data 9 /* 10 {"success":"登錄成功"} 11 {"error":"用戶名不存在"} 12 {"error":"密碼不正確"} 13 */ 14 if (data) {//請求成功 15 NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil]; 16 NSLog(@"%@",dict); 17 18 //判斷後,在界面提示登錄信息 19 NSString *error=dict[@"error"]; 20 if (error) { 21 [MBProgressHUD showError:error]; 22 }else 23 { 24 NSString *success=dict[@"success"]; 25 [MBProgressHUD showSuccess:success]; 26 } 27 }else //請求失敗 28 { 29 [MBProgressHUD showError:@"網絡繁忙,請稍後重試!"]; 30 } 31 32 }];解析data
//解析data /* {"success":"登錄成功"} {"error":"用戶名不存在"} {"error":"密碼不正確"} */說明:使用NSJSONSerialization 返回的對象,取決於最外層是什麼,如果是{}那就是字典,[]那就是數組等。 補充說明: 首先確定請求路徑,然後創建請求對象(默認發送的時get請求),使用異步方法(一調用這個方法,它會自動開啟一個子線程去發送請求,當請求成功,數據返回的時候自動調用內部的代碼段,這個代碼段在那個線程執行取決於隊列,如果是主隊列,那麼在子線程發送請求成功拿到服務器的數據後,回到主線程中解析數據,刷新UI界面)。 B.使用代理方法發送異步請求
要監聽服務器返回的data,所以使用<NSURLConnectionDataDelegate>協議
常見大代理方法如下:
1 #pragma mark- NSURLConnectionDataDelegate代理方法 2 3 //當接收到服務器的響應(連通了服務器)時會調用 4 5 -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 6 7 //當接收到服務器的數據時會調用(可能會被調用多次,每次只傳遞部分數據) 8 9 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 10 11 //當服務器的數據加載完畢時就會調用 12 13 -(void)connectionDidFinishLoading:(NSURLConnection *)connection 14 15 //請求錯誤(失敗)的時候調用(請求超時\斷網\沒有網\,一般指客戶端錯誤) 16 17 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
使用異步方法發送get請求的代碼示例:
1 // 2 // YYViewController.m 3 // 01-NSURLConnection的使用(GET) 4 // 5 // Created by apple on 14-6-28. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 #import "MBProgressHUD+MJ.h" 11 12 @interface YYViewController ()<NSURLConnectionDataDelegate> 13 @property (weak, nonatomic) IBOutlet UITextField *username; 14 @property (weak, nonatomic) IBOutlet UITextField *pwd; 15 @property(nonatomic,strong)NSMutableData *responseData; 16 - (IBAction)login; 17 18 @end 19 20 @implementation YYViewController 21 22 - (IBAction)login { 23 // 1.提前的表單驗證 24 if (self.username.text.length==0) { 25 [MBProgressHUD showError:@"請輸入用戶名"]; 26 return; 27 } 28 if (self.pwd.text.length==0) { 29 [MBProgressHUD showError:@"請輸入密碼"]; 30 return; 31 } 32 // 2.發送請求給服務器(帶上賬號和密碼) 33 //添加一個遮罩,禁止用戶操作 34 [MBProgressHUD showMessage:@"正在努力加載中...."]; 35 36 // 37 // 2.1設置請求路徑 38 NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/login?username=%@&pwd=%@",self.username.text,self.pwd.text]; 39 NSURL *url=[NSURL URLWithString:urlStr]; 40 41 // 2.2創建請求對象 42 // NSURLRequest *request=[NSURLRequest requestWithURL:url];//默認就是GET請求 43 //設置請求超時 44 NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:url]; 45 request.timeoutInterval=5.0; 46 47 // 2.3.發送請求 48 //使用代理發送異步請求(通常應用於文件下載) 49 NSURLConnection *conn=[NSURLConnection connectionWithRequest:request delegate:self]; 50 [conn start]; 51 NSLog(@"已經發出請求---"); 52 } 53 54 #pragma mark- NSURLConnectionDataDelegate代理方法 55 /* 56 *當接收到服務器的響應(連通了服務器)時會調用 57 */ 58 -(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response 59 { 60 NSLog(@"接收到服務器的響應"); 61 //初始化數據 62 self.responseData=[NSMutableData data]; 63 } 64 65 /* 66 *當接收到服務器的數據時會調用(可能會被調用多次,每次只傳遞部分數據) 67 */ 68 -(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data 69 { 70 NSLog(@"接收到服務器的數據"); 71 //拼接數據 72 [self.responseData appendData:data]; 73 NSLog(@"%d---%@--",self.responseData.length,[NSThread currentThread]); 74 } 75 76 /* 77 *當服務器的數據加載完畢時就會調用 78 */ 79 -(void)connectionDidFinishLoading:(NSURLConnection *)connection 80 { 81 NSLog(@"服務器的數據加載完畢"); 82 //隱藏HUD 83 [MBProgressHUD hideHUD]; 84 85 //處理服務器返回的所有數據 86 NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:nil]; 87 88 //判斷後,在界面提示登錄信息 89 NSString *error=dict[@"error"]; 90 if (error) { 91 [MBProgressHUD showError:error]; 92 }else 93 { 94 NSString *success=dict[@"success"]; 95 [MBProgressHUD showSuccess:success]; 96 } 97 NSLog(@"%d---%@--",self.responseData.length,[NSThread currentThread]); 98 } 99 /* 100 *請求錯誤(失敗)的時候調用(請求超時\斷網\沒有網\,一般指客戶端錯誤) 101 */ 102 -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 103 { 104 // NSLog(@"請求錯誤"); 105 //隱藏HUD 106 [MBProgressHUD hideHUD]; 107 [MBProgressHUD showError:@"網絡繁忙,請稍後重試!"]; 108 } 109 @end
打印查看:
補充:
(1)數據的處理
在didReceiveData:方法中,拼接接收到的所有數據,等所有數據都拿到後,在connectionDidFinishLoading:方法中進行處理
(2)網絡延遲
在做網絡開發的時候,一定要考慮到網絡延遲情況的處理,可以在服務器的代碼設置一個斷點模擬。
在服務器代碼的登錄方法中設置斷點
設置請求的最大延遲
模擬器情況:
打印查看:
三、NSMutableURLRequest
NSMutableURLRequest是NSURLRequest的子類,常用方法有
設置請求超時等待時間(超過這個時間就算超時,請求失敗)- (void)setTimeoutInterval:(NSTimeInterval)seconds;
設置請求方法(比如GET和POST)- (void)setHTTPMethod:(NSString *)method;
設置請求體- (void)setHTTPBody:(NSData *)data;
設置請求頭- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field;