前言:

无论是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];

根据需求添加不用的设置,比如请求方式、超时时间、请求头信息,这里重点介绍下缓存策略:

  • 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 = [NSURLSession sharedSession];

可以通过NSURLSessionConfiguration方式配置不同的NSURLSession

    // 构造NSURLSessionConfiguration
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
// 构造NSURLSession,网络会话;
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration];

通过NSURLSessionConfiguration提供了三种创建NSURLSession的方式

  • defaultSessionConfiguration //默认配置使用的是持久化的硬盘缓存,存储证书到用户钥匙链。存储cookie到shareCookie。
  • ephemeralSessionConfiguration //不使用永久持存cookie、证书、缓存的配置,最佳优化数据传输。
  • backgroundSessionConfigurationWithIdentifier //可以上传下载HTTP和HTTPS的后台任务(程序在后台运行)。
    在后台时,将网络传输交给系统的单独的一个进程,即使app挂起、推出甚至崩溃照样在后台执行。

也可以通过NSURLSessionConfiguration统一设置超时时间、请求头等信息

    // 构造NSURLSessionConfiguration
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
//设置请求超时为10秒钟
configuration.timeoutIntervalForRequest = ; //在蜂窝网络情况下是否继续请求(上传或下载)
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

  • NSURLSessionDataTask  //一般的get、post等请求
  • NSURLSessionUploadTask // 用于上传文件或者数据量比较大的请求
  • NSURLSessionDownloadTask //用于下载文件或者数据量比较大的请求
  • NSURLSessionStreamTask //建立一个TCP / IP连接的主机名和端口或一个网络服务对象。

task的三个函数

  • - (void)suspend;//暂停
  • - (void)resume;//开始或者恢复
  • - (void)cancel;//关闭任务

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":@""};
// 4.2、遍历字典,以“key=value&”的方式创建参数字符串。
NSMutableString *parameterString = [[NSMutableString alloc]init];
int pos =;
for (NSString *key in parametersDict.allKeys) {
// 拼接字符串
[parameterString appendFormat:@"%@=%@", key, parametersDict[key]];
if(pos<parametersDict.allKeys.count-){
[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:];
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",@"",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(, ));
}];
});
} else {
NSLog(@"download error : %@", error.localizedDescription);
}
}];
//启动任务
[downLoadTask resume];

总结:

今天学习了iOS底层如何实现网络请求的,为了开发效率还得依靠优秀的第三方开源框架,接下来抽时间学习一下受广大iOS开发者亲赖的网络开源框架AFNetWorking。

最新文章

  1. 利用SQLServer数据库发送邮件
  2. LOCK TABLES和UNLOCK TABLES与Transactions的交互
  3. CWMP开源代码研究3——ACS介绍
  4. 在jquery的ajax中添加自定义的header信息
  5. 关于浏览器兼容问题及hack写法
  6. Wish You to Remember
  7. wpf,CollectionViewSource,使用数据过滤 筛选 功能。
  8. matlab学习笔记 bsxfun函数
  9. Manacher 算法(hdu 3068 &amp;&amp; hdu 3294)
  10. C++容器和算法
  11. error at ::0 can&#39;t find referenced pointcut performance
  12. QT 的信号与槽机制介绍
  13. 了不起的分支和循环01 - 零基础入门学习Python007
  14. Spring学习(3)---Spring设值注入和构造注入
  15. 用servlet进行用户名和密码校验
  16. spring boot集成aop实现日志记录
  17. MFC中psz_data无法读取内存的错误
  18. PDO中的事务处理
  19. 创建HTML元素的方法
  20. The key unit of modularity in OOP is the class, whereas in AOP the unit of modularity is the aspect.

热门文章

  1. c循环程序
  2. 在octave语言中K-means聚类算法求聚类中心的向量化计算
  3. github 更新fork分支
  4. 扩展对EasyUI的校验规则
  5. STM32/GD32芯片信息(转)
  6. BZOJ 1653 [Usaco2006 Feb]Backward Digit Sums ——搜索
  7. UVa 10400 - Game Show Math
  8. logback的日志配置文件
  9. Delphi总结使用TStrings的一些技巧
  10. Delphi流的操作