iOS開發(fā)網(wǎng)絡篇—NSURLConnection基本使用
一低散、NSURLConnection的常用類
(1)NSURL:請求地址
(2)NSURLRequest:封裝一個請求鳍烁,保存發(fā)給服務器的全部數(shù)據(jù)啊楚,包括一個NSURL對象叮趴,請求方法逊彭、請求頭然磷、請求體....
(3)NSMutableURLRequest:NSURLRequest的子類
(4)NSURLConnection:負責發(fā)送請求紫谷,建立客戶端和服務器的連接挣输。發(fā)送NSURLRequest的數(shù)據(jù)給服務器纬凤,并收集來自服務器的響應數(shù)據(jù)
二、NSURLConnection的使用
1.簡單說明
使用NSURLConnection發(fā)送請求的步驟很簡單
(1)創(chuàng)建一個NSURL對象撩嚼,設置請求路徑(設置請求路徑)
(2)傳入NSURL創(chuàng)建一個NSURLRequest對象停士,設置請求頭和請求體(創(chuàng)建請求對象)
(3)使用NSURLConnection發(fā)送NSURLRequest(發(fā)送請求)
2.代碼示例
(1)發(fā)送請求的三個步驟:
1.設置請求路徑
2.創(chuàng)建請求對象
3.發(fā)送請求
3.1發(fā)送同步請求(一直在等待服務器返回數(shù)據(jù),這行代碼會卡住完丽,如果服務器恋技,沒有返回數(shù)據(jù),那么在主線程UI會卡住不能繼續(xù)執(zhí)行操作)有返回值
3.2發(fā)送異步請求:沒有返回值
說明:任何NSURLRequest默認都是get請求逻族。
(2)發(fā)送同步請求代碼示例:
1//2//YYViewController.m3//01-NSURLConnection的使用(GET)4//5//Created by apple on 14-6-28.6//Copyright (c) 2014年 itcase. All rights reserved.7//89#import"YYViewController.h"10#import"MBProgressHUD+MJ.h"1112@interfaceYYViewController ()13@property (weak, nonatomic) IBOutlet UITextField *username;14@property (weak, nonatomic) IBOutlet UITextField *pwd;15-(IBAction)login;1617@end1819@implementationYYViewController2021-(IBAction)login {22//1.提前的表單驗證23if(self.username.text.length==0) {24[MBProgressHUD showError:@"請輸入用戶名"];25return;26}27if(self.pwd.text.length==0) {28[MBProgressHUD showError:@"請輸入密碼"];29return;30}31//2.發(fā)送請求給服務器(帶上賬號和密碼)32//添加一個遮罩蜻底,禁止用戶操作33//[MBProgressHUD showMessage:@"正在努力加載中...."];34//GET請求:請求行\(zhòng)請求頭\請求體35//36//1.設置請求路徑37NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/login?username=%@&pwd=%@",self.username.text,self.pwd.text];38NSURL *url=[NSURL URLWithString:urlStr];39//2.創(chuàng)建請求對象40NSURLRequest *request=[NSURLRequest requestWithURL:url];41//3.發(fā)送請求42//發(fā)送同步請求,在主線程執(zhí)行43NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];44//(一直在等待服務器返回數(shù)據(jù)聘鳞,這行代碼會卡住薄辅,如果服務器沒有返回數(shù)據(jù),那么在主線程UI會卡住不能繼續(xù)執(zhí)行操作)45NSLog(@"--%d--",data.length);46}47@end
模擬器情況:
打印服務器返回的信息:
補充說明:
1.提前的表單驗證
2.發(fā)送請求給服務器(帶上賬號和密碼)
GET請求:請求行\(zhòng)請求頭\請求體
注意:GET請求中不存在請求體抠璃,因為所有的信息都寫在URL里面站楚。在IOS里面,請求行和請求頭都不用寫搏嗡。
(3)發(fā)送異步請求
發(fā)送異步請求有兩種方式:
1)使用block回調
2)代理
A.使用block回調方法發(fā)送異步請求
使用block回調代碼示例:
1//2//YYViewController.m3//01-NSURLConnection的使用(GET)4//5//Created by apple on 14-6-28.6//Copyright (c) 2014年 itcase. All rights reserved.7//89#import"YYViewController.h"10#import"MBProgressHUD+MJ.h"1112@interfaceYYViewController ()13@property (weak, nonatomic) IBOutlet UITextField *username;14@property (weak, nonatomic) IBOutlet UITextField *pwd;15-(IBAction)login;1617@end1819@implementationYYViewController2021-(IBAction)login {22//1.提前的表單驗證23if(self.username.text.length==0) {24[MBProgressHUD showError:@"請輸入用戶名"];25return;26}27if(self.pwd.text.length==0) {28[MBProgressHUD showError:@"請輸入密碼"];29return;30}31//2.發(fā)送請求給服務器(帶上賬號和密碼)32//添加一個遮罩窿春,禁止用戶操作33[MBProgressHUD showMessage:@"正在努力加載中...."];3435//36//1.設置請求路徑37NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/login?username=%@&pwd=%@",self.username.text,self.pwd.text];38NSURL *url=[NSURL URLWithString:urlStr];3940//2.創(chuàng)建請求對象41NSURLRequest *request=[NSURLRequest requestWithURL:url];4243//3.發(fā)送請求44//3.1發(fā)送同步請求,在主線程執(zhí)行45//NSData *data=[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];46//(一直在等待服務器返回數(shù)據(jù)采盒,這行代碼會卡住旧乞,如果服務器沒有返回數(shù)據(jù),那么在主線程UI會卡住不能繼續(xù)執(zhí)行操作)4748//3.1發(fā)送異步請求49//創(chuàng)建一個隊列(默認添加到該隊列中的任務異步執(zhí)行)50//NSOperationQueue *queue=[[NSOperationQueue alloc]init];51//獲取一個主隊列52NSOperationQueue *queue=[NSOperationQueue mainQueue];53[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {54NSLog(@"--block回調數(shù)據(jù)--%@---%d", [NSThread currentThread],data.length);55//隱藏HUD纽甘,刷新UI的操作一定要放在主線程執(zhí)行56[MBProgressHUD hideHUD];5758//解析data59/*60{"success":"登錄成功"}61{"error":"用戶名不存在"}62{"error":"密碼不正確"}63*/64NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];65NSLog(@"%@",dict);6667//判斷后良蛮,在界面提示登錄信息68NSString *error=dict[@"error"];69if(error) {70[MBProgressHUD showError:error];71}else72{73NSString *success=dict[@"success"];74[MBProgressHUD showSuccess:success];75}76}];77NSLog(@"請求發(fā)送完畢");78}79@end
模擬器情況(注意這里使用了第三方框架):
打印查看:
代碼說明:
block代碼段:當服務器有返回數(shù)據(jù)的時候調用會開一條新的線程去發(fā)送請求,主線程繼續(xù)往下走悍赢,當拿到服務器的返回數(shù)據(jù)的數(shù)據(jù)的時候再回調block决瞳,執(zhí)行block代碼段货徙。這種情況不會卡住主線程。
隊列的作用:決定這個block操作放在哪個線程執(zhí)行皮胡?
刷新UI界面的操作應該放在主線程執(zhí)行痴颊,不能放在子線程,在子線程處理UI相關操作會出現(xiàn)一些莫名的問題屡贺。
提示:
(1)創(chuàng)建一個操作蠢棱,放在NSOperation隊列中執(zhí)行,默認是異步執(zhí)行的甩栈。
(2)mainqueue ? 返回一個和主線程相關的隊列泻仙,即主隊列。
新的問題:如果向服務器發(fā)送請求量没,卻并沒有拿到數(shù)據(jù)玉转,那么程序會崩潰(data不能為空)
改進代碼:
1NSOperationQueue *queue=[NSOperationQueue mainQueue];2[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {3//當請求結束的時候調用(有兩種結果,一個是成功拿到數(shù)據(jù)殴蹄,也可能沒有拿到數(shù)據(jù)究抓,請求失敗)4NSLog(@"--block回調數(shù)據(jù)--%@---%d", [NSThread currentThread],data.length);5//隱藏HUD袭灯,刷新UI的操作一定要放在主線程執(zhí)行6[MBProgressHUD hideHUD];78//解析data9/*10{"success":"登錄成功"}11{"error":"用戶名不存在"}12{"error":"密碼不正確"}13*/14if(data) {//請求成功15NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];16NSLog(@"%@",dict);1718//判斷后刺下,在界面提示登錄信息19NSString *error=dict[@"error"];20if(error) {21[MBProgressHUD showError:error];22}else23{24NSString *success=dict[@"success"];25[MBProgressHUD showSuccess:success];26}27}else//請求失敗28{29[MBProgressHUD showError:@"網(wǎng)絡繁忙,請稍后重試稽荧!"];30}3132}];
解析data
//解析data/*{"success":"登錄成功"}
{"error":"用戶名不存在"}
{"error":"密碼不正確"}*/
說明:使用NSJSONSerialization 返回的對象橘茉,取決于最外層是什么,如果是{}那就是字典姨丈,[]那就是數(shù)組等捺癞。
補充說明:
首先確定請求路徑,然后創(chuàng)建請求對象(默認發(fā)送的時get請求)构挤,使用異步方法(一調
用這個方法,它會自動開啟一個子線程去發(fā)送請求惕鼓,當請求成功筋现,數(shù)據(jù)返回的時候自動調用內(nèi)部的代碼段,這個代碼段在那個線程執(zhí)行取決于隊列箱歧,如果是主隊列矾飞,
那么在子線程發(fā)送請求成功拿到服務器的數(shù)據(jù)后,回到主線程中解析數(shù)據(jù)呀邢,刷新UI界面)洒沦。
B.使用代理方法發(fā)送異步請求
要監(jiān)聽服務器返回的data,所以使用協(xié)議
常見大代理方法如下:
1#pragmamark- NSURLConnectionDataDelegate代理方法23//當接收到服務器的響應(連通了服務器)時會調用45-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response67//當接收到服務器的數(shù)據(jù)時會調用(可能會被調用多次价淌,每次只傳遞部分數(shù)據(jù))89-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data1011//當服務器的數(shù)據(jù)加載完畢時就會調用1213-(void)connectionDidFinishLoading:(NSURLConnection *)connection1415//請求錯誤(失斏暄邸)的時候調用(請求超時\斷網(wǎng)\沒有網(wǎng)\瞒津,一般指客戶端錯誤)1617-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
使用異步方法發(fā)送get請求的代碼示例:
1//2//YYViewController.m3//01-NSURLConnection的使用(GET)4//5//Created by apple on 14-6-28.6//Copyright (c) 2014年 itcase. All rights reserved.7//89#import"YYViewController.h"10#import"MBProgressHUD+MJ.h"1112@interfaceYYViewController ()13@property (weak, nonatomic) IBOutlet UITextField *username;14@property (weak, nonatomic) IBOutlet UITextField *pwd;15@property(nonatomic,strong)NSMutableData *responseData;16-(IBAction)login;1718@end1920@implementationYYViewController2122-(IBAction)login {23//1.提前的表單驗證24if(self.username.text.length==0) {25[MBProgressHUD showError:@"請輸入用戶名"];26return;27}28if(self.pwd.text.length==0) {29[MBProgressHUD showError:@"請輸入密碼"];30return;31}32//2.發(fā)送請求給服務器(帶上賬號和密碼)33//添加一個遮罩,禁止用戶操作34[MBProgressHUD showMessage:@"正在努力加載中...."];3536//37//2.1設置請求路徑38NSString *urlStr=[NSString stringWithFormat:@"http://192.168.1.53:8080/MJServer/login?username=%@&pwd=%@",self.username.text,self.pwd.text];39NSURL *url=[NSURL URLWithString:urlStr];4041//2.2創(chuàng)建請求對象42//NSURLRequest *request=[NSURLRequest requestWithURL:url];//默認就是GET請求43//設置請求超時44NSMutableURLRequest *request=[NSMutableURLRequest? requestWithURL:url];45request.timeoutInterval=5.0;4647//2.3.發(fā)送請求48//使用代理發(fā)送異步請求(通常應用于文件下載)49NSURLConnection *conn=[NSURLConnection connectionWithRequest:requestdelegate:self];50[conn start];51NSLog(@"已經(jīng)發(fā)出請求---");52}5354#pragmamark- NSURLConnectionDataDelegate代理方法55/*56*當接收到服務器的響應(連通了服務器)時會調用57*/58-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response59{60NSLog(@"接收到服務器的響應");61//初始化數(shù)據(jù)62self.responseData=[NSMutableData data];63}6465/*66*當接收到服務器的數(shù)據(jù)時會調用(可能會被調用多次括尸,每次只傳遞部分數(shù)據(jù))67*/68-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data69{70NSLog(@"接收到服務器的數(shù)據(jù)");71//拼接數(shù)據(jù)72[self.responseData appendData:data];73NSLog(@"%d---%@--",self.responseData.length,[NSThread currentThread]);74}7576/*77*當服務器的數(shù)據(jù)加載完畢時就會調用78*/79-(void)connectionDidFinishLoading:(NSURLConnection *)connection80{81NSLog(@"服務器的數(shù)據(jù)加載完畢");82//隱藏HUD83[MBProgressHUD hideHUD];8485//處理服務器返回的所有數(shù)據(jù)86NSDictionary *dict=[NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:nil];8788//判斷后巷蚪,在界面提示登錄信息89NSString *error=dict[@"error"];90if(error) {91[MBProgressHUD showError:error];92}else93{94NSString *success=dict[@"success"];95[MBProgressHUD showSuccess:success];96}97NSLog(@"%d---%@--",self.responseData.length,[NSThread currentThread]);98}99/*100*請求錯誤(失敗)的時候調用(請求超時\斷網(wǎng)\沒有網(wǎng)\濒翻,一般指客戶端錯誤)101*/102-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error103{104//NSLog(@"請求錯誤");105//隱藏HUD106[MBProgressHUD hideHUD];107[MBProgressHUD showError:@"網(wǎng)絡繁忙屁柏,請稍后重試!"];108}109@end
打印查看:
補充:
(1)數(shù)據(jù)的處理
在didReceiveData:方法中有送,拼接接收到的所有數(shù)據(jù)淌喻,等所有數(shù)據(jù)都拿到后,在connectionDidFinishLoading:方法中進行處理
(2)網(wǎng)絡延遲
在做網(wǎng)絡開發(fā)的時候雀摘,一定要考慮到網(wǎng)絡延遲情況的處理裸删,可以在服務器的代碼設置一個斷點模擬。
在服務器代碼的登錄方法中設置斷點
設置請求的最大延遲
模擬器情況:
打印查看:
三届宠、NSMutableURLRequest
NSMutableURLRequest是NSURLRequest的子類烁落,常用方法有
設置請求超時等待時間(超過這個時間就算超時,請求失斖阕ⅰ)- (void)setTimeoutInterval:(NSTimeInterval)seconds;
設置請求方法(比如GET和POST)- (void)setHTTPMethod:(NSString *)method;
設置請求體- (void)setHTTPBody:(NSData *)data;
設置請求頭- (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field;