IOS网络请求之NSURLSession使用详解
前言:
无论是Android还是ios都离不开与服务器交互,这就必须用到网络请求,记得在2013年做iOS的时候那时候用的ASIHTTPRequest框架,现在重新捡起iOS的时候ASIHTTPRequest已经停止维护,大家都在用AFNetWorking作为首选网络请求框架,之前的ASIHTTPRequest是基于NSURLConnection类实现的,早期的AFNetWorking也是基于NSURLConnection实现,后来iOS9之后已经放弃了NSURLConnection,开始使用iOS7之后推出的NSURLSession,本着追根溯源的原则,首先学习一下NSURLSession的实现网络请求,然后再去学习AFNetWorking。
了解NSURLSession
NSURLSession是2013年iOS7发布的用于替代NSURLConnection的,iOS9之后NSURLConnection彻底推出历史舞台。其使用起来非常方便,今天使用NSURLConnection分别实现了get、post、表单提交、文件上传、文件下载,让我这个以Android开发为主的屌丝程序员赞叹不已,根据NSURLSession会话对象创建一个请求Task,然后执行该Task即可,包括缓存、会话周期,多线程任务iOS都已经在sdk层面封装完毕,不过比较遗憾的时NSURLSession只提供了异步请求方式而没有提供同步请求方式。接下来我们来如何实现网络请求。
NSURLSession使用
我们首先以一个简单的get请求为例开始。
1.)首先构造一个NSURL请求资源地址
//构造URL资源地址 NSURL*url=[NSURLURLWithString:@http://api.nohttp.net/method?name=yanzhenjie&pwd=123];
2.)创建一个NSRequest请求对象
//创建Request请求
NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:url];
//配置Request请求
//设置请求方法
[requestsetHTTPMethod:@"GET"];
//设置请求超时默认超时时间60s
[requestsetTimeoutInterval:10.0];
//设置头部参数
[requestaddValue:@"gzip"forHTTPHeaderField:@"Content-Encoding"];
//或者下面这种方式添加所有请求头信息
request.allHTTPHeaderFields=@{@"Content-Encoding":@"gzip"};
//设置缓存策略
[requestsetCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
根据需求添加不用的设置,比如请求方式、超时时间、请求头信息,这里重点介绍下缓存策略:
- NSURLRequestUseProtocolCachePolicy=0//默认的缓存策略,如果缓存不存在,直接从服务端获取。如果缓存存在,会根据response中的Cache-Control字段判断下一步操作,如:Cache-Control字段为must-revalidata,则询问服务端该数据是否有更新,无更新的话直接返回给用户缓存数据,若已更新,则请求服务端.
- NSURLRequestReloadIgnoringLocalCacheData=1//忽略本地缓存数据,直接请求服务端.
- NSURLRequestIgnoringLocalAndRemoteCacheData=4//忽略本地缓存,代理服务器以及其他中介,直接请求源服务端.
- NSURLRequestReloadIgnoringCacheData=NSURLRequestReloadIgnoringLocalCacheData
- NSURLRequestReturnCacheDataElseLoad=2//有缓存就使用,不管其有效性(即忽略Cache-Control字段),无则请求服务端.
- NSURLRequestReturnCacheDataDontLoad=3//只加载本地缓存.没有就失败.(确定当前无网络时使用)
- NSURLRequestReloadRevalidatingCacheData=5//缓存数据必须得得到服务端确认有效才使用
3.)创建NSURLSession会话对象
可以通过采用iOS共享Session的方式
//采用苹果提供的共享session NSURLSession*sharedSession=[NSURLSessionsharedSession];
可以通过NSURLSessionConfiguration方式配置不同的NSURLSession
//构造NSURLSessionConfiguration NSURLSessionConfiguration*configuration=[NSURLSessionConfigurationdefaultSessionConfiguration]; //构造NSURLSession,网络会话; NSURLSession*session=[NSURLSessionsessionWithConfiguration:configuration];
通过NSURLSessionConfiguration提供了三种创建NSURLSession的方式
- defaultSessionConfiguration//默认配置使用的是持久化的硬盘缓存,存储证书到用户钥匙链。存储cookie到shareCookie。
- ephemeralSessionConfiguration//不使用永久持存cookie、证书、缓存的配置,最佳优化数据传输。
- backgroundSessionConfigurationWithIdentifier//可以上传下载HTTP和HTTPS的后台任务(程序在后台运行)。
在后台时,将网络传输交给系统的单独的一个进程,即使app挂起、推出甚至崩溃照样在后台执行。
也可以通过NSURLSessionConfiguration统一设置超时时间、请求头等信息
//构造NSURLSessionConfiguration
NSURLSessionConfiguration*configuration=[NSURLSessionConfigurationdefaultSessionConfiguration];
//设置请求超时为10秒钟
configuration.timeoutIntervalForRequest=10;
//在蜂窝网络情况下是否继续请求(上传或下载)
configuration.allowsCellularAccess=NO;
//配置请求头
configuration.HTTPAdditionalHeaders=@{@"Content-Encoding":@"gzip"};
4.)创建NSURLSessionTask对象,然后执行
//构造NSURLSessionTask,会话任务;
NSURLSessionDataTask*task=[sessiondataTaskWithRequest:requestcompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
//请求失败,打印错误信息
if(error){
NSLog(@"geterror:%@",error.localizedDescription);
}
//请求成功,解析数据
else{
//JSON数据格式解析
idobject=[NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingMutableLeaveserror:&error];
//判断是否解析成功
if(error){
NSLog(@"geterror:%@",error.localizedDescription);
}else{
NSLog(@"getsuccess:%@",object);
//解析成功,处理数据,通过GCD获取主队列,在主线程中刷新界面。
dispatch_async(dispatch_get_main_queue(),^{
//刷新界面....
});
}
}
}];
iOS为了适应不同的应用场景提供了不同类型的NSSessionTask
- NSURLSessionDataTask //一般的get、post等请求
- NSURLSessionUploadTask//用于上传文件或者数据量比较大的请求
- NSURLSessionDownloadTask//用于下载文件或者数据量比较大的请求
- NSURLSessionStreamTask//建立一个TCP/IP连接的主机名和端口或一个网络服务对象。
task的三个函数
- -(void)suspend;//暂停
- -(void)resume;//开始或者恢复
- -(void)cancel;//关闭任务
NSURLSession其他请求示例
1.)post请求
//1、创建URL资源地址
NSURL*url=[NSURLURLWithString:@"http://api.nohttp.net/postBody"];
//2、创建Reuest请求
NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:url];
//3、配置Request
//设置请求超时
[requestsetTimeoutInterval:10.0];
//设置请求方法
[requestsetHTTPMethod:@"POST"];
//设置头部参数
[requestaddValue:@"gzip"forHTTPHeaderField:@"Content-Encoding"];
//4、构造请求参数
//4.1、创建字典参数,将参数放入字典中,可防止程序员在主观意识上犯错误,即参数写错。
NSDictionary*parametersDict=@{@"name":@"yanzhenjie",@"pwd":@"123"};
//4.2、遍历字典,以“key=value&”的方式创建参数字符串。
NSMutableString*parameterString=[[NSMutableStringalloc]init];
intpos=0;
for(NSString*keyinparametersDict.allKeys){
//拼接字符串
[parameterStringappendFormat:@"%@=%@",key,parametersDict[key]];
if(pos<parametersDict.allKeys.count-1){
[parameterStringappendString:@"&"];
}
pos++;
}
//4.3、NSString转成NSData数据类型。
NSData*parametersData=[parameterStringdataUsingEncoding:NSUTF8StringEncoding];
//5、设置请求报文
[requestsetHTTPBody:parametersData];
//6、构造NSURLSessionConfiguration
NSURLSessionConfiguration*configuration=[NSURLSessionConfigurationdefaultSessionConfiguration];
//7、创建网络会话
NSURLSession*session=[NSURLSessionsessionWithConfiguration:configuration];
//8、创建会话任务
NSURLSessionDataTask*task=[sessiondataTaskWithRequest:requestcompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
//10、判断是否请求成功
if(error){
NSLog(@"posterror:%@",error.localizedDescription);
}else{
//如果请求成功,则解析数据。
idobject=[NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingMutableLeaveserror:&error];
//11、判断是否解析成功
if(error){
NSLog(@"posterror:%@",error.localizedDescription);
}else{
//解析成功,处理数据,通过GCD获取主队列,在主线程中刷新界面。
NSLog(@"postsuccess:%@",object);
dispatch_async(dispatch_get_main_queue(),^{
//刷新界面...
});
}
}
}];
//9、执行任务
[taskresume];
2.)附带表单参数文件上传
NSDate*dat=[NSDatedateWithTimeIntervalSinceNow:0];
NSTimeIntervala=[dattimeIntervalSince1970];
NSString*fileName=[NSStringstringWithFormat:@"file_%0.f.txt",a];
[FileUtilswriteDataToFile:fileNamedata:[@"upload_file_to_server"dataUsingEncoding:NSUTF8StringEncoding]];
//以流的方式上传,大小理论上不受限制,但应注意时间
//1、创建URL资源地址
NSURL*url=[NSURLURLWithString:@"http://api.nohttp.net/upload"];
//2、创建Reuest请求
NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:url];
//3、配置Request
//设置Body值方法二,这种方法比较原始,不常用,不过可以用来上传参数和文件
NSString*BOUNDARY=@"whoislcj";//表单分界线可以自定义任意值
[requestsetValue:[@"multipart/form-data;boundary="stringByAppendingString:BOUNDARY]forHTTPHeaderField:@"Content-Type"];
//文件上传使用post
[requestsetHTTPMethod:@"POST"];
//设置请求超时
[requestsetTimeoutInterval:30.0f];
//用于存放二进制数据流
NSMutableData*body=[NSMutableDatadata];
//追加一个普通表单参数name=yanzhenjie
NSString*nameParam=[NSStringstringWithFormat:@"--%@\r\nContent-Disposition:form-data;name=\"%@\"\r\n\r\n%@\r\n",BOUNDARY,@"name",@"yanzhenjie",nil];
[bodyappendData:[nameParamdataUsingEncoding:NSUTF8StringEncoding]];
//追加一个普通表单参数pwd=123
NSString*pwdParam=[NSStringstringWithFormat:@"--%@\r\nContent-Disposition:form-data;name=\"%@\"\r\n\r\n%@\r\n",BOUNDARY,@"pwd",@"123",nil];
[bodyappendData:[pwdParamdataUsingEncoding:NSUTF8StringEncoding]];
//追加一个文件表单参数
//Content-Disposition:form-data;name="<服务器端需要知道的名字>";filename="<服务器端这个传上来的文件名>"
//Content-Type:application/octet-stream--根据不同的文件类型选择不同的值
NSString*file=[NSStringstringWithFormat:@"--%@\r\nContent-Disposition:form-data;name=\"%@\";filename=\"%@\"\r\nContent-Type:application/octet-stream\r\n\r\n",BOUNDARY,@"headUrl",fileName,nil];
[bodyappendData:[filedataUsingEncoding:NSUTF8StringEncoding]];
//获取file路径
NSString*filePath=[FileUtilsgetFilePath:fileName];
NSData*data=[NSDatadataWithContentsOfFile:filePath];
//追加文件二进制数据
[bodyappendData:data];
[bodyappendData:[@"\r\n"dataUsingEncoding:NSUTF8StringEncoding]];
//结束分割线
NSString*endString=[NSStringstringWithFormat:@"--%@--",BOUNDARY];
[bodyappendData:[endStringdataUsingEncoding:NSUTF8StringEncoding]];
//创建会话
NSURLSession*session=[NSURLSessionsharedSession];
//3.开始上传request的bodydata将被忽略,而由fromData提供
NSURLSessionUploadTask*uploadTask=[sessionuploadTaskWithRequest:requestfromData:bodycompletionHandler:^(NSData*_Nullabledata,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
if(error){
NSLog(@"uploaderror:%@",error);
}else{
NSLog(@"uploadsuccess:%@",[NSJSONSerializationJSONObjectWithData:dataoptions:NSJSONReadingMutableLeaveserror:&error]);
dispatch_async(dispatch_get_main_queue(),^{
//刷新界面...
});
}
}];
//执行任务
[uploadTaskresume];
3.)文件下载
//创建url
NSString*urlStr=@"http://images2015.cnblogs.com/blog/950883/201701/950883-20170105104233581-62069155.png";
NSURL*Url=[NSURLURLWithString:urlStr];
//创建请求
NSMutableURLRequest*request=[NSMutableURLRequestrequestWithURL:Url];
//设置请求超时
[requestsetTimeoutInterval:30.0];
//创建会话
NSURLSession*session=[NSURLSessionsharedSession];
NSURLSessionDownloadTask*downLoadTask=[sessiondownloadTaskWithRequest:requestcompletionHandler:^(NSURL*_Nullablelocation,NSURLResponse*_Nullableresponse,NSError*_Nullableerror){
if(!error){
NSLog(@"downloadsucess:%@",location);
NSData*data=[NSDatadataWithContentsOfURL:location];
UIImage*image=[UIImageimageWithData:data];
dispatch_async(dispatch_get_main_queue(),^{
//刷新界面...
UIImageView*imageView=[[UIImageViewalloc]init];
imageView.image=image;
[self.viewaddSubview:imageView];
[imageViewmas_makeConstraints:^(MASConstraintMaker*make){
make.center.equalTo(self.view);
make.size.mas_equalTo(CGSizeMake(300,300));
}];
});
}else{
NSLog(@"downloaderror:%@",error.localizedDescription);
}
}];
//启动任务
[downLoadTaskresume];
总结:
今天学习了iOS底层如何实现网络请求的,为了开发效率还得依靠优秀的第三方开源框架,以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。