IOS网络请求之AFNetWorking 3.x 使用详情
前言:
计划把公司的网络请求与业务解耦,所以想着学习一下网络请求,最近学习了nsurlsession,今天来学习一下基于nsurlsession封装的优秀开源框架afnetworking 3.x,之前13年做ios开发时用的asihttprequest开源框架。
afnetworking
afnetworking一款轻量级网络请求开源框架,基于ios和mac os 网络进行扩展的高性能框架,大大降低了ios开发工程师处理网络请求的难度,让ios开发变成一件愉快的事情。
1.)afhttpsessionmanager请求管理者
-(afhttpsessionmanager *)sharedmanager { afhttpsessionmanager *manager = [afhttpsessionmanager manager]; //最大请求并发任务数 manager.operationqueue.maxconcurrentoperationcount = 5; // 请求格式 // afhttprequestserializer 二进制格式 // afjsonrequestserializer json // afpropertylistrequestserializer plist(是一种特殊的xml,解析起来相对容易) manager.requestserializer = [afhttprequestserializer serializer]; // 上传普通格式 // 超时时间 manager.requestserializer.timeoutinterval = 30.0f; // 设置请求头 [manager.requestserializer setvalue:@"gzip" forhttpheaderfield:@"content-encoding"]; // 设置接收的content-type manager.responseserializer.acceptablecontenttypes = [[nsset alloc] initwithobjects:@"application/xml", @"text/xml",@"text/html", @"application/json",@"text/plain",nil]; // 返回格式 // afhttpresponseserializer 二进制格式 // afjsonresponseserializer json // afxmlparserresponseserializer xml,只能返回xmlparser,还需要自己通过代理方法解析 // afxmldocumentresponseserializer (mac os x) // afpropertylistresponseserializer plist // afimageresponseserializer image // afcompoundresponseserializer 组合 manager.responseserializer = [afjsonresponseserializer serializer];//返回格式 json //设置返回c的ontent-type manager.responseserializer.acceptablecontenttypes=[[nsset alloc] initwithobjects:@"application/xml", @"text/xml",@"text/html", @"application/json",@"text/plain",nil]; return manager; }
2.)处理get请求
-(void)dogetrequest { //创建请求地址 nsstring *url=@"http://api.nohttp.net/method"; //构造参数 nsdictionary *parameters=@{@"name":@"yanzhenjie",@"pwd":@"123"}; //afn管理者调用get请求方法 [[self shareafnmanager] get:url parameters:parameters progress:^(nsprogress * _nonnull downloadprogress) { //返回请求返回进度 nslog(@"downloadprogress-->%@",downloadprogress); } success:^(nsurlsessiondatatask * _nonnull task, id _nullable responseobject) { //请求成功返回数据 根据responseserializer 返回不同的数据格式 nslog(@"responseobject-->%@",responseobject); } failure:^(nsurlsessiondatatask * _nullable task, nserror * _nonnull error) { //请求失败 nslog(@"error-->%@",error); }]; }
3.)处理post请求
-(void)dopostrequestofafn { //创建请求地址 nsstring *url=@"http://api.nohttp.net/postbody"; //构造参数 nsdictionary *parameters=@{@"name":@"yanzhenjie",@"pwd":@"123"}; //afn管理者调用get请求方法 [[self shareafnmanager] post:url parameters:parameters progress:^(nsprogress * _nonnull uploadprogress) { //返回请求返回进度 nslog(@"downloadprogress-->%@",uploadprogress); } success:^(nsurlsessiondatatask * _nonnull task, id _nullable responseobject) { //请求成功返回数据 根据responseserializer 返回不同的数据格式 nslog(@"responseobject-->%@",responseobject); } failure:^(nsurlsessiondatatask * _nullable task, nserror * _nonnull error) { //请求失败 nslog(@"error-->%@",error); }]; }
4.)处理文件上传
-(void)douploadrequest { // 创建url资源地址 nsstring *url = @"http://api.nohttp.net/upload"; // 参数 nsdictionary *parameters=@{@"name":@"yanzhenjie",@"pwd":@"123"}; [[self shareafnmanager] post:url parameters:parameters constructingbodywithblock:^(id<afmultipartformdata> _nonnull formdata) { 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]]; // 获取数据转换成data nsstring *filepath =[fileutils getfilepath:filename]; // 拼接数据到请求题中 [formdata appendpartwithfileurl:[nsurl fileurlwithpath:filepath] name:@"headurl" filename:filename mimetype:@"application/octet-stream" error:nil]; } progress:^(nsprogress * _nonnull uploadprogress) { // 上传进度 nslog(@"%lf",1.0 *uploadprogress.completedunitcount / uploadprogress.totalunitcount); } success:^(nsurlsessiondatatask * _nonnull task, id _nullable responseobject) { //请求成功 nslog(@"请求成功:%@",responseobject); } failure:^(nsurlsessiondatatask * _nullable task, nserror * _nonnull error) { //请求失败 nslog(@"请求失败:%@",error); }]; }
5.)处理文件下载
-(void)dodownloadrequest { nsstring *urlstr =@"http://images2015.cnblogs.com/blog/950883/201701/950883-20170105104233581-62069155.png"; // 设置请求的url地址 nsurl *url = [nsurl urlwithstring:urlstr]; // 创建请求对象 nsurlrequest *request = [nsurlrequest requestwithurl:url]; // 下载任务 nsurlsessiondownloadtask *task = [[self shareafnmanager] downloadtaskwithrequest:request progress:^(nsprogress * _nonnull downloadprogress) { // 下载进度 nslog(@"当前下载进度为:%lf", 1.0 * downloadprogress.completedunitcount / downloadprogress.totalunitcount); } destination:^nsurl * _nonnull(nsurl * _nonnull targetpath, nsurlresponse * _nonnull response) { // 下载地址 nslog(@"默认下载地址%@",targetpath); //这里模拟一个路径 真实场景可以根据url计算出一个md5值 作为filekey nsdate* dat = [nsdate datewithtimeintervalsincenow:0]; nstimeinterval a=[dat timeintervalsince1970]; nsstring* filekey = [nsstring stringwithformat:@"/file_%0.f.txt", a]; // 设置下载路径,通过沙盒获取缓存地址,最后返回nsurl对象 nsstring *filepath = [fileutils getfilepath:filekey]; return [nsurl fileurlwithpath:filepath]; // 返回的是文件存放在本地沙盒的地址 } completionhandler:^(nsurlresponse * _nonnull response, nsurl * _nullable filepath, nserror * _nullable error) { // 下载完成调用的方法 nslog(@"filepath---%@", filepath); nsdata *data=[nsdata datawithcontentsofurl:filepath]; uiimage *image=[uiimage imagewithdata:data]; // 刷新界面... 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)); }]; }]; //启动下载任务 [task resume]; }
6.)网络状态监听
- (void)afnetworkstatus{ //创建网络监测者 afnetworkreachabilitymanager *manager = [afnetworkreachabilitymanager sharedmanager]; /*枚举里面四个状态 分别对应 未知 无网络 数据 wifi typedef ns_enum(nsinteger, afnetworkreachabilitystatus) { afnetworkreachabilitystatusunknown = -1, 未知 afnetworkreachabilitystatusnotreachable = 0, 无网络 afnetworkreachabilitystatusreachableviawwan = 1, 蜂窝数据网络 afnetworkreachabilitystatusreachableviawifi = 2, wifi }; */ [manager setreachabilitystatuschangeblock:^(afnetworkreachabilitystatus status) { //这里是监测到网络改变的block 可以写成switch方便 //在里面可以随便写事件 switch (status) { case afnetworkreachabilitystatusunknown: nslog(@"未知网络状态"); break; case afnetworkreachabilitystatusnotreachable: nslog(@"无网络"); break; case afnetworkreachabilitystatusreachableviawwan: nslog(@"蜂窝数据网"); break; case afnetworkreachabilitystatusreachableviawifi: nslog(@"wifi网络"); break; default: break; } }] ; [manager startmonitoring]; }
afnetworking内存泄露
通常情况我们一般会认为以manager结尾的都是单例模式,所以我们一般都是这样使用afnetworking,如下
afhttpsessionmanager *manager = [afhttpsessionmanager manager];
其实我们点进去查看源码发现并不是单例,而是每次都实例化一个afhttpsessionmanager对象,源码如下
+ (instancetype)manager { return [[[self class] alloc] initwithbaseurl:nil]; }
所以我们在使用afnetworking的时候要对afhttpsessionmanager进行单例封装
+ (afhttpsessionmanager *)sharedmanager { static afhttpsessionmanager *manager = nil; static dispatch_once_t predicate; dispatch_once(&predicate, ^{ manager = [afhttpsessionmanager manager]; manager.operationqueue.maxconcurrentoperationcount = 5; manager.requestserializer.timeoutinterval=30.f; manager.responseserializer.acceptablecontenttypes = [[nsset alloc] initwithobjects:@"application/xml", @"text/xml",@"text/html", @"application/json",@"text/plain",nil]; [manager.requestserializer setvalue:@"gzip" forhttpheaderfield:@"content-encoding"]; }); return manager; }
afnetworking关于https
在2017年1月1日起apple 要求开发者于年底之前为提交至 app store 中的应用启用 https ,以支持 ios 9 引入的 ats(app transport security)技术。但后来,apple 发布声明宣布延长这个时限,提供给开发者更多的时间进行相关准备。目前 apple 尚未公布新的截止日期。所以目前应对https的方案有两种。
第一种方式:
屏蔽调ios ats(app transport security),在plist.info文件中添加如下代码
<key>nsapptransportsecurity</key> <dict> <key>nsallowsarbitraryloads</key> <true/> </dict>
第二种方式:
配置https ca证书,这里采用获取nsbundle中获取ca证书,afnetworking提供了配置afsecuritypolicy模块
+ (afsecuritypolicy *)customsecuritypolicy{ //https ca证书地址 nsstring *cerpath = [[nsbundle mainbundle] pathforresource:@"xueletshttps" oftype:@"cer"]; //获取ca证书数据 nsdata *cerdata = [nsdata datawithcontentsoffile:cerpath]; //创建afsecuritypolicy对象 afsecuritypolicy *security = [afsecuritypolicy policywithpinningmode:afsslpinningmodenone]; //设置是否允许不信任的证书(证书无效、证书时间过期)通过验证 ,默认为no. security.allowinvalidcertificates = yes; //是否验证域名证书的cn(common name)字段。默认值为yes。 security.validatesdomainname = no; //根据验证模式来返回用于验证服务器的证书 security.pinnedcertificates = [nsset setwithobject:cerdata]; return security; }
然后通过设置afhttpsessionmanager的securitypolicy属性等于自定义的afsecuritypolicy。
总结:
简单记录一下afnetworking的基本使用,方便以后查找。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。