当前位置: 移动技术网 > IT编程>移动开发>IOS > iOS在页面销毁时如何优雅的cancel网络请求详解

iOS在页面销毁时如何优雅的cancel网络请求详解

2019年07月24日  | 移动技术网IT编程  | 我要评论

前言

大家都知道,当一个网络请求发出去之后,如果不管不顾,有可能出现以下情况:

进入某个页面,做了某种操作(退出页面、切换某个tab等等)导致之前的请求变成无用请求,这时候有可能出现虽然页面已经销毁了,但是网络请求还在外面飞的情况,如果放任不管,那么这个请求既浪费流量,又浪费性能,尤其是在网络比较差时,一个超时的无用请求更让人不爽。这时候,我们最好的办法是cancel掉这些无用的请求。

传统的cancel方式是这样的:

1.在类里面需要持有请求对象

@property (strong/weak, nonatomic) xxrequest *xxrequest1; 

属性具体用strong还是weak取决于你的网络层设计,有些网络层request是完全的临时变量,出了方法就直接销毁的需要用strong,有些设计则具有自持有的特性,请求结束前不会销毁的可以用weak。

2.在请求发起的地方,赋值请求

xxrequest1 = xxx;
self.xxrequest1 = xxrequest1;
[xxrequest1 start];

3.在需要销毁的地方,一般是本类的dealloc里面

[self.xxrequest1 cancel];

可以看到为了cancel一个request,我们的请求对象到处都是,如果再来几个请求,那处理起来就更恶心了。。

有没有什么方式可以让我们省心省力呢?

目标:

我们希望可以控制一部分请求,在页面销毁、manager释放等时机,自动的cancel掉我们发出去的请求,而不需要我们手动去写上面这种到处都是的代码

方案:

监听类的dealloc方法调用,当dealloc执行时,顺带着执行下request的cancel方法

很快,我们就发现了问题:

arc下不允许hook类的dealloc方法,所以hook是不行的。那还有别的方式可以知道一个类被dealloc了吗?

其实我们可以采用一些变通的方案得到,我们知道associated绑定的属性,是可以根据绑定时的设置,在dealloc时自动释放的,所以我们可以利用这一点做到监听dealloc调用:

  • 构建一个中间类a,该类在销毁执行dealloc时,顺便执行请求的cancel方法
  • 通过associate绑定的方式,将销毁类绑定到任意执行类b上
  • 这样,当执行类b销毁时,销毁内部的associate的属性时,我们就可以得到相应的执行时机。

下面给出核心代码:

创建用于cancel请求的类:

@interface yrweakrequest : nsobject
@property (weak, nonatomic) id request;
@end
@implementation yrweakrequest
@end

2.构建用于记录某类绑定所有请求的类

@interface yrdeallocrequests : nsobject
@property (strong, nonatomic) nsmutablearray<yrweakrequest*> *weakrequests;
@property (strong, nonatomic) nslock *lock;
@end
@implementation yrdeallocrequests
- (instancetype)init{
 if (self = [super init]) {
 _weakrequests = [nsmutablearray arraywithcapacity:20];
 _lock = [[nslock alloc]init];
 }
 return self;
}
- (void)addrequest:(yrweakrequest*)request{
 if (!request||!request.request) {
 return;
 }
 [_lock lock];
 [self.weakrequests addobject:request];
 [_lock unlock];
}
- (void)cleardeallocrequest{
 [_lock lock];
 nsinteger count = self.weakrequests.count;
 for (nsinteger i=count-1; i>0; i--) {
 yrweakrequest *weakrequest = self.weakrequests[i];
 if (!weakrequest.request) {
  [self.weakrequests removeobject:weakrequest];
 }
 }
 [_lock unlock];
}
- (void)dealloc{
 for (yrweakrequest *weakrequest in _weakrequests) {
 [weakrequest.request cancel];
 }
}
@end

3.对任意类绑定该中间类

@implementation nsobject (yrrequest)

- (yrdeallocrequests *)deallocrequests{
 yrdeallocrequests *requests = objc_getassociatedobject(self, _cmd);
 if (!requests) {
 requests = [[yrdeallocrequests alloc]init];
 objc_setassociatedobject(self, _cmd, requests, objc_association_retain_nonatomic);
 }
 return requests;
}

- (void)autocancelrequestondealloc:(id)request{
 [[self deallocrequests] cleardeallocrequest];
 yrweakrequest *weakrequest = [[yrweakrequest alloc] init];
 weakrequest.request = request;
 [[self deallocrequests] addrequest:weakrequest];
}
@end

4.对外暴露的头文件

@interface nsobject (yrrequest)
/*!
 * @brief add request to auto cancel when obj dealloc
 * @note will call request's cancel method , so the request must have cancel method..
 */
- (void)autocancelrequestondealloc:(id)request;
@end

使用方式

怎么样,看头文件是不是觉得很简单,使用方式就很简单了,

比如说我们需要在某个vc里,释放时自动cancel网络请求:

//请求发起的地方:
xxrequest1 = xxx;
[xxrequest1 start];
[self autocancelrequestondealloc:xxrequest1];

好了,从此不再担心该类销毁时请求乱飞了。

其他:

1.我的实现类里面,默认调用的是cancel方法,所以理论上,所有带有cancel方法的request都可以直接用这个方法调用(如afnetworking、nsurlsessiontask等等)

2.有些人会说,我是用自己的网络层,自己封装的requset发起的请求,不调用cancel,自己封装的对象也会销毁的;我要提醒的是,有可能你自己封装的对象销毁了,但是其下层,无论对接的是af还是系统的,又或者是其他的请求库,一定是具有自持有性质的,如果不这么说,风险在于数据返回前底层的请求就会销毁掉,一般不会有人这么设计的。

3.例子中我绑定的是self,其实还可以绑定到任意对象上,比如某个类的内部属性等等,这样可以根据业务需求进一步控制请求的cancel时机

附上github地址,欢迎指正:https://github.com/yueruo/nsobject_autocancelrequest ()

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

  • ios uicollectionview实现横向滚动

    现在使用卡片效果的app很多,之前公司让实现一种卡片效果,就写了一篇关于实现卡片的文章。文章最后附有demo实现上我选择了使用uicollectionview ... [阅读全文]
  • iOS UICollectionView实现横向滑动

    本文实例为大家分享了ios uicollectionview实现横向滑动的具体代码,供大家参考,具体内容如下uicollectionview的横向滚动,目前我使... [阅读全文]
  • iOS13适配深色模式(Dark Mode)的实现

    iOS13适配深色模式(Dark Mode)的实现

    好像大概也许是一年前, mac os系统发布了深色模式外观, 看着挺刺激, 时至今日用着也还挺爽的终于, 随着iphone11等新手机的发售, ios 13系统... [阅读全文]
  • ios 使用xcode11 新建项目工程的步骤详解

    ios 使用xcode11 新建项目工程的步骤详解

    xcode11新建项目工程,新增了scenedelegate这个类,转而将原appdelegate负责的对ui生命周期的处理担子接了过来。故此可以理解为:ios... [阅读全文]
  • iOS实现转盘效果

    本文实例为大家分享了ios实现转盘效果的具体代码,供大家参考,具体内容如下demo下载地址: ios转盘效果功能:实现了常用的ios转盘效果,轮盘抽奖效果的实现... [阅读全文]
  • iOS开发实现转盘功能

    本文实例为大家分享了ios实现转盘功能的具体代码,供大家参考,具体内容如下今天给同学们讲解一下一个转盘选号的功能,直接上代码直接看viewcontroller#... [阅读全文]
  • iOS实现轮盘动态效果

    本文实例为大家分享了ios实现轮盘动态效果的具体代码,供大家参考,具体内容如下一个常用的绘图,主要用来打分之类的动画,效果如下。主要是ios的绘图和动画,本来想... [阅读全文]
  • iOS实现九宫格连线手势解锁

    本文实例为大家分享了ios实现九宫格连线手势解锁的具体代码,供大家参考,具体内容如下demo下载地址:效果图:核心代码://// clockview.m// 手... [阅读全文]
  • iOS实现卡片堆叠效果

    本文实例为大家分享了ios实现卡片堆叠效果的具体代码,供大家参考,具体内容如下如图,这就是最终效果。去年安卓5.0发布的时候,当我看到安卓全新的material... [阅读全文]
  • iOS利用余弦函数实现卡片浏览工具

    iOS利用余弦函数实现卡片浏览工具

    本文实例为大家分享了ios利用余弦函数实现卡片浏览工具的具体代码,供大家参考,具体内容如下一、实现效果通过拖拽屏幕实现卡片移动,左右两侧的卡片随着拖动变小,中间... [阅读全文]
验证码:
移动技术网