循环引用问题:NSTimer正确使用方式、block注意问题

循环引用问题,就是2个或多个对象相互拥有,互相都没办法先释放自己.
在这里插入图片描述
实际问题可能会更复杂,例如3个/多个互相拥有关系,此时肉眼看代码,很容易被逻辑绕晕.即使创始人很理智,以后的接手人也会被绕晕.
里面有循环引用吗?分别是哪几个?
平时要培养好代码的低耦合,高内聚习惯.比较容易出现的循环引用的情况:
1、@property(strong 这玩意什么时候该用weak,就得用weak,别贪图方便,全部strong.
2、NSTimer iOS10.0之前很容易出现循环引用,当然如果您在iOS10.0后还是使用旧方法,依然容易出现循环引用
3、block ,对block一知半解,直接copy过来,然后就开始糊糊涂涂地使用,也会很容易出现循环引用

第一点:略,因为真的没啥写的,如果犯第一点循环引用的,都是明知故犯者,建议望天吧.
第二点:可以看看https://github.com/wyuyung/YungTimer.鄙人简单封装一个控件.
为啥NSTimer会引起循环引用?在iOS10.0之前,大部分人是这么使用NSTimer的:
@property(nonatomic, strong) NSTimer *timer;
_timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(handleTimerRun) userInfo:nil repeats:YES];
此时self拥有timer, timer计数+1.
计时器初始化时, 因为target:self ,timer便拥有self,self计数+1.
所以循环引用问题出现了,self拥有timer,timer拥有self.谁先自动释放呢?这个循环引用怎么能方便地解决呢?(答案自行从YungTimer项目中寻找)

第三点:我们还是看YungTimer项目,iOS10.0之后,我们可以用block.因为没有了target,就没有了上面的第二点 target:self 的问题.但是block的不正当使用,也是会引发循环引用的.举个爪子:
先定义一个_num.
@interface YungTimer () {
int _num;
}
然后在block里面自增,统计次数.
_timer = [NSTimer scheduledTimerWithTimeInterval:interval repeats:YES block:^(NSTimer * _Nonnull timer) {
_num++;
}];
这段代码逻辑有啥问题呢?
答案是:
1、block运行_num++代码时,这个block便拥有了self. (为啥呢?因为block里面的_num++;会编译成self->_num++; block里面使用了任何变量,都会在构造函数上对这个变量进行计数+1.self->_num是C语言的写法,它的意思是访问指针,然后从指针中对应的地址取某一个存储区域对应的值.所以block拥有的不是_num,而是self)
2、self拥有timer,timer拥有block.所以相当于self拥有了block.

block拥有了self.self拥有了block.循环引用又出来了.

那么要怎么做呢?self拥有block.这是不可能更改的,那么只能更改block拥有self了.我们可以这么做,新增一个weakself代替self给block使用:
__weak typeof(self)weakSelf = self;
_timer = [NSTimer scheduledTimerWithTimeInterval:interval repeats:YES block:^(NSTimer * _Nonnull timer) {
weakSelf->_num++;
}];
但是为什么会报错误呢?
有些人为了解决这个错误,会这样子写:
@interface YungTimer ()
@property(nonatomic, assign) int num;

__weak typeof(self)weakSelf = self;
_timer = [NSTimer scheduledTimerWithTimeInterval:interval repeats:YES block:^(NSTimer * _Nonnull timer) {
weakSelf._num++;
}];
错误没了,运行正常,提交代码,上架审核,然后走上人生癫疯.
上面这写法虽然没有什么错误或异常,运行也不会出什么大的bug,但是属于瞎猫抓到瞎老鼠,纯属靠望天.

个人写法如下:
__weak typeof(self)weakSelf = self;
_timer = [NSTimer scheduledTimerWithTimeInterval:interval repeats:YES block:^(NSTimer * _Nonnull timer) {
__strong typeof(weakSelf)strongSelf = weakSelf;
if (!strongSelf) {
//此处可以做一些self被释放后的异常操作,调用一些单例函数,例如统计
return;
}
strongSelf->_num++; //strongSelf._num++;
}];
__weak __strong是block的关键字,主要的作用是为了避开block在构建函数时对self计数+1.只在使用的时候__strong计数+1,使用完成后就会计数-1(这个是函数生命周期决定的).避开了构建时对self计数+1,析构时对self计数-1.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值