前言:
無論是Android還是ios都離不開與服務器交互,這就必須用到網絡請求,記得在2013年做iOS的時候那時候用的ASIHTTPRequest框架,現在重新撿起iOS的時候ASIHTTPRequest已經停止維護,大家都在用AFNetWorking作為首選網絡請求框架,之前的ASIHTTPRequest是基於NSURLConnection類實現的,早期的AFNetWorking也是基於NSURLConnection實現,後來iOS9 之後已經放棄了NSURLConnection,開始使用iOS 7之後推出的NSURLSession,本著追根溯源的原則,首先學習一下NSURLSession的實現網絡請求,然後再去學習AFNetWorking。
了解NSURLSession
NSURLSession是2013年iOS 7發布的用於替代NSURLConnection的,iOS 9之後NSURLConnection徹底推出歷史舞台。其使用起來非常方便,今天使用NSURLConnection分別實現了get、post、表單提交、文件上傳、文件下載,讓我這個以Android開發為主的屌絲程序員贊歎不已,根據NSURLSession會話對象創建一個請求Task,然後執行該Task即可,包括緩存、會話周期,多線程任務iOS都已經在sdk層面封裝完畢,不過比較遺憾的時NSURLSession只提供了異步請求方式而沒有提供同步請求方式。接下來我們來如何實現網絡請求。
NSURLSession使用
我們首先以一個簡單的get請求為例開始。
1.)首先構造一個NSURL請求資源地址
// 構造URL資源地址 NSURL *url = [NSURL URLWithString:@http://api.nohttp.net/method?name=yanzhenjie&pwd=123];
2.)創建一個NSRequest請求對象
// 創建Request請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 配置Request請求 // 設置請求方法 [request setHTTPMethod:@"GET"]; // 設置請求超時 默認超時時間60s [request setTimeoutInterval:10.0]; // 設置頭部參數 [request addValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"]; //或者下面這種方式 添加所有請求頭信息 request.allHTTPHeaderFields=@{@"Content-Encoding":@"gzip"}; //設置緩存策略 [request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
根據需求添加不用的設置,比如請求方式、超時時間、請求頭信息,這裡重點介紹下緩存策略:
3.)創建NSURLSession會話對象
可以通過采用iOS共享Session的方式
// 采用蘋果提供的共享session NSURLSession *sharedSession = [NSURLSession sharedSession];
可以通過NSURLSessionConfiguration方式配置不同的NSURLSession
// 構造NSURLSessionConfiguration NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; // 構造NSURLSession,網絡會話; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];
通過NSURLSessionConfiguration提供了三種創建NSURLSession的方式
在後台時,將網絡傳輸交給系統的單獨的一個進程,即使app掛起、推出甚至崩潰照樣在後台執行。
也可以通過NSURLSessionConfiguration統一設置超時時間、請求頭等信息
// 構造NSURLSessionConfiguration NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; //設置請求超時為10秒鐘 configuration.timeoutIntervalForRequest = 10; //在蜂窩網絡情況下是否繼續請求(上傳或下載) configuration.allowsCellularAccess = NO; //配置請求頭 configuration.HTTPAdditionalHeaders =@{@"Content-Encoding":@"gzip"};
4.) 創建NSURLSessionTask對象,然後執行
// 構造NSURLSessionTask,會話任務; NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 請求失敗,打印錯誤信息 if (error) { NSLog(@"get error :%@",error.localizedDescription); } //請求成功,解析數據 else { // JSON數據格式解析 id object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; // 判斷是否解析成功 if (error) { NSLog(@"get error :%@",error.localizedDescription); }else { NSLog(@"get success :%@",object); // 解析成功,處理數據,通過GCD獲取主隊列,在主線程中刷新界面。 dispatch_async(dispatch_get_main_queue(), ^{ // 刷新界面.... }); } } }];
iOS為了適應不同的應用場景提供了不同類型的NSSessionTask
task的三個函數
NSURLSession其他請求示例
1.)post請求
// 1、創建URL資源地址 NSURL *url = [NSURL URLWithString:@"http://api.nohttp.net/postBody"]; // 2、創建Reuest請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 3、配置Request // 設置請求超時 [request setTimeoutInterval:10.0]; // 設置請求方法 [request setHTTPMethod:@"POST"]; // 設置頭部參數 [request addValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"]; // 4、構造請求參數 // 4.1、創建字典參數,將參數放入字典中,可防止程序員在主觀意識上犯錯誤,即參數寫錯。 NSDictionary *parametersDict = @{@"name":@"yanzhenjie",@"pwd":@"123"}; // 4.2、遍歷字典,以“key=value&”的方式創建參數字符串。 NSMutableString *parameterString = [[NSMutableString alloc]init]; int pos =0; for (NSString *key in parametersDict.allKeys) { // 拼接字符串 [parameterString appendFormat:@"%@=%@", key, parametersDict[key]]; if(pos<parametersDict.allKeys.count-1){ [parameterString appendString:@"&"]; } pos++; } // 4.3、NSString轉成NSData數據類型。 NSData *parametersData = [parameterString dataUsingEncoding:NSUTF8StringEncoding]; // 5、設置請求報文 [request setHTTPBody:parametersData]; // 6、構造NSURLSessionConfiguration NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; // 7、創建網絡會話 NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; // 8、創建會話任務 NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 10、判斷是否請求成功 if (error) { NSLog(@"post error :%@",error.localizedDescription); }else { // 如果請求成功,則解析數據。 id object = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]; // 11、判斷是否解析成功 if (error) { NSLog(@"post error :%@",error.localizedDescription); }else { // 解析成功,處理數據,通過GCD獲取主隊列,在主線程中刷新界面。 NSLog(@"post success :%@",object); dispatch_async(dispatch_get_main_queue(), ^{ // 刷新界面... }); } } }]; // 9、執行任務 [task resume];
2.)附帶表單參數文件上傳
NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:0]; NSTimeInterval a=[dat timeIntervalSince1970]; NSString* fileName = [NSString stringWithFormat:@"file_%0.f.txt", a]; [FileUtils writeDataToFile:fileName data:[@"upload_file_to_server" dataUsingEncoding:NSUTF8StringEncoding]]; // 以流的方式上傳,大小理論上不受限制,但應注意時間 // 1、創建URL資源地址 NSURL *url = [NSURL URLWithString:@"http://api.nohttp.net/upload"]; // 2、創建Reuest請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 3、配置Request //設置Body值方法二,這種方法比較原始,不常用,不過可以用來上傳參數和文件 NSString *BOUNDARY = @"whoislcj";//表單分界線 可以自定義任意值 [request setValue:[@"multipart/form-data; boundary=" stringByAppendingString:BOUNDARY] forHTTPHeaderField:@"Content-Type"]; // 文件上傳使用post [request setHTTPMethod:@"POST"]; // 設置請求超時 [request setTimeoutInterval:30.0f]; //用於存放二進制數據流 NSMutableData *body = [NSMutableData data]; //追加一個普通表單參數 name=yanzhenjie NSString *nameParam = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n",BOUNDARY,@"name",@"yanzhenjie",nil]; [body appendData:[nameParam dataUsingEncoding:NSUTF8StringEncoding]]; //追加一個普通表單參數 pwd=123 NSString *pwdParam = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n%@\r\n",BOUNDARY,@"pwd",@"123",nil]; [body appendData:[pwdParam dataUsingEncoding:NSUTF8StringEncoding]]; //追加一個文件表單參數 // Content-Disposition: form-data; name="<服務器端需要知道的名字>"; filename="<服務器端這個傳上來的文件名>" // Content-Type: application/octet-stream --根據不同的文件類型選擇不同的值 NSString *file = [NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\";filename=\"%@\"\r\nContent-Type: application/octet-stream\r\n\r\n",BOUNDARY,@"headUrl",fileName,nil]; [body appendData:[file dataUsingEncoding:NSUTF8StringEncoding]]; //獲取file路徑 NSString *filePath =[FileUtils getFilePath:fileName]; NSData *data =[NSData dataWithContentsOfFile:filePath]; //追加文件二進制數據 [body appendData:data]; [body appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; //結束分割線 NSString *endString = [NSString stringWithFormat:@"--%@--",BOUNDARY]; [body appendData:[endString dataUsingEncoding:NSUTF8StringEncoding]]; // 創建會話 NSURLSession *session = [NSURLSession sharedSession]; // 3.開始上傳 request的body data將被忽略,而由fromData提供 NSURLSessionUploadTask *uploadTask= [session uploadTaskWithRequest:request fromData:body completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { NSLog(@"upload error:%@",error); } else { NSLog(@"upload success:%@", [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error]); dispatch_async(dispatch_get_main_queue(), ^{ // 刷新界面... }); } }]; //執行任務 [uploadTask resume];
3.)文件下載
// 創建url NSString *urlStr =@"http://images2015.cnblogs.com/blog/950883/201701/950883-20170105104233581-62069155.png"; NSURL *Url = [NSURL URLWithString:urlStr]; // 創建請求 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:Url]; // 設置請求超時 [request setTimeoutInterval:30.0]; // 創建會話 NSURLSession *session = [NSURLSession sharedSession]; NSURLSessionDownloadTask *downLoadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (!error) { NSLog(@"download sucess : %@", location); NSData *data=[NSData dataWithContentsOfURL:location]; UIImage *image=[UIImage imageWithData:data]; dispatch_async(dispatch_get_main_queue(), ^{ // 刷新界面... UIImageView *imageView =[[UIImageView alloc]init]; imageView.image=image; [self.view addSubview:imageView]; [imageView mas_makeConstraints:^(MASConstraintMaker *make) { make.center.equalTo(self.view); make.size.mas_equalTo(CGSizeMake(300, 300)); }]; }); } else { NSLog(@"download error : %@", error.localizedDescription); } }]; //啟動任務 [downLoadTask resume];
總結:
今天學習了iOS底層如何實現網絡請求的,為了開發效率還得依靠優秀的第三方開源框架,以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。