日常开发最常用的定时方法还是NSTimer,CADisplayLink跟GCDTimer写起来还是略麻烦。但是对于重复的任务有一个重要问题:何时停掉这个任务。而且NSTimer经常会出现循环引用的问题,因此整合记录下。
情况一:
Timer会强持有target,所以如果我们写个vc持有一个Timer,并且这个Timer初始化以vc为target,那就循环引用了
![](https://img.haomeiwen.com/i1785849/21b0ad78d6814630.png)
结果:
![](https://img.haomeiwen.com/i1785849/3cce8bc49ffeb7ef.png)
循环情况:
![](https://img.haomeiwen.com/i1785849/4b97db7eb70ab506.png)
这种情况下即便我们pop了TestVC,testvc dealloc依然不会出现,控制台会无限制打印a
解决方法:
合适的情况下调用timer.invalidate()手动停掉timer,打破循环:
![](https://img.haomeiwen.com/i1785849/068289b6fdf62fa3.png)
![](https://img.haomeiwen.com/i1785849/7ca5f4d05c9a06ec.png)
情况二:
那如果我们不持有这个timer,在某个方法里timer只是作为一个局部变量来一vc为target,这样testvc就不会抢引用timer,是否可以避免循环引用?
![](https://img.haomeiwen.com/i1785849/1798b01f939fdc25.png)
结果:
![](https://img.haomeiwen.com/i1785849/d622897e86313fab.png)
依然未释放。这是因为启动timer时需要把timer添加到当前runloop中,那当前runloop就会持有timer如果不调用timer的invalidate方法,这个timer就无法被runloop释放,timer所持有的target也无法被释放。(scheduledTimer方法相当于initTimer() + fire() + runloop.addTimer()三合一)
![](https://img.haomeiwen.com/i1785849/0a0e12f0c85ec8ae.png)
解决方法:
标记这个timer,合适的时候手动停掉
综合解决方案:在合适的时候停掉timer
思路:使用中间target:
![](https://img.haomeiwen.com/i1785849/79aac89d79a1dbcc.png)
使用一个InnerTarget,初始化Timer时,InnerTarget弱持有testvc,持有selector,弱持有testvc,timer强引用InnerTarget,在InnerTarget的selector中,使用weak target来调用selector方法,这样testvc就可以正常dealloc,当testvc释放时,InnerTarget可以感知,停止Timer即可实现自动释放timer:
![](https://img.haomeiwen.com/i1785849/6ef16d164c3c47a2.png)
再试试看:
![](https://img.haomeiwen.com/i1785849/44982d0a680c3a58.png)
![](https://img.haomeiwen.com/i1785849/71dd2013bb5b635c.png)
正常释放
iOS10 新增的block初始化Timer的方法,解决了Timer强引用target的问题,但是无法解决Runloop持有Timer的问题,仍然需要手动释放timer
尝试:使用stopTarget+block来初始化Timer,使用思路类似于Target:
![](https://img.haomeiwen.com/i1785849/cf21c54523d72e0d.png)
使用:
![](https://img.haomeiwen.com/i1785849/43ce97d4d5b1000b.png)
![](https://img.haomeiwen.com/i1785849/4db15f239caa248b.png)
可以正常释放
缺点:
因为block会对内部对象进行一次引用计数+1所以如果block里出现了self,请一定要使用weak self。否则依然会出现循环引用情况:
![](https://img.haomeiwen.com/i1785849/03d24eb78aad8e2f.png)
引用图:
![](https://img.haomeiwen.com/i1785849/ef6cd6514d9b418b.png)
使用weak/unowned self可打破引用问题:
![](https://img.haomeiwen.com/i1785849/a62e339fa69a04d8.png)
引用图:
![](https://img.haomeiwen.com/i1785849/b891b32ad2ed0a7d.png)
网友评论