前段时间用到一次定时器功能,发现的一个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]];