前段时间用到一次定时器功能,发现的一个NStimer定时器内存泄漏的问题。于是在整个项目中查找用到定时器的地方,并进行修改。
定时器比较常用的是下面2个方法:
|
|
Runloop是保持程序的持续运行,处理各类事件的机制,其中就包括NSTimer。
其中scheduledTimerWithTimeInterval方法创建的定时器是自动加入Runloop的,并且默认是DefaultMode模式。
而timerWithTimeInterval则需要自己手动加入Runloop才能触发。一般会设置为CommonModel模式,这样就不会受UI的影响而保持定时器正常工作。
我一直都是用后者,并且一直以为在delloc中像以下方法释放就OK了。
|
|
但是发现这并不能释放。定时器依旧会照常工作,且不会运行dealloc方法。
原因就是
|
|
这里target传入的self会被timer强引用,而timer又被self强引用。这样就形成了引用循环了。
那这样行不行:
|
|
或者给timer一个weak弱引用,或者传入target一个弱引用的self。
以上经实验都不行,其实timer已经加入到Runloop里面了,timer如果没有从Runloop里面移除,那这个对象将一直存在。唯一能将timer移除Runloop的就只有[timer invalidate];方法。所以当你不用定时器的时候必须执行以下方法释放:
|
|
这里参考了这个做法iOS 中的 NSTimer不用target传self,而是传一个Bolck来处理事件。
可以写个分类,代码如下:
|
|
最后了解下NSTimer的暂停和开始
开始定时的方法就是将fireDate设置在过去的某一个时间:
[self.timer setFireDate:[NSDate distantPast]];
暂停的方法就是把fireDate设置在未来的某一个时间:
[self.timer setFireDate:[NSDate distantFuture]];