iOS定时器平时用的比较多,原理比较简单,但是真正用对却不是哪么简单。本篇就目前比较常用的定时器以及使用过程中需要注意的问题讲解一下,如有不对的地方,欢迎指正
第一类定时器 NSTimer
- 创建一个NSTimer对象
1.主要分为两类,一类是需要单独加到runloop中的,另一类是不需要单独加到runloop中的。我们可以到NSTimer的头文件中去查看。需要做添加到runloop中的初始化方法有三个:
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- (instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(nullable id)ui repeats:(BOOL)rep NS_DESIGNATED_INITIALIZER;
不需要加到runloop中的初始化方法有两个,默认添加到当前线程所在的runloop中
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(nullable id)userInfo repeats:(BOOL)yesOrNo;
- 如何让一个定时器开始工作
1.初始化完成之后,不做任何干预,哪么定时器会在ti秒之后执行。
2.如果想让定时器在初始化完成之后立刻执行,可以调用NSTimer的fire方法。
3.如果想让定时器暂停,并且在另外一个时间开启,可以按照下面的方式
[self.timer setFireDate:[NSDate distantFuture]]; //暂停一个正在执行中的Timer
[self.timer setFireDate:[NSDate distantPast]]; //开始执行一个执行中的Timer
-
第一个坑 循环引用
借用一个图来表示一下
千万不要试图在OneViewController的dealloc方法中释放掉Timer,因为如果这种循环引用不被打破,OneViewController将永远都不会被释放,也就不会走dealloc方法。
- 解决的方法有两种
1.在ViewWillDisAppear中做释放Timer操作
2.在业务需要停掉Timer的时候 做Timer的释放操作
3.打破这种循环引用,也就是让timer的target不要设为self,而是设置为另外一个类,这样就可以在controller被销毁的时候 正确的释放掉Timer。 - 释放Timer的正确姿势是:
[self.timer invalidate];
self.timer = nil;
-
第二个坑 计时不准
如果在Timer所在的线程正在做比较耗时的操作,哪么很可能会导致Timer计时不准,解决的方法也比较简单,可以使用GCD Timer,单独开一个线程做计时操作。
第三个坑,Timer失效
这个坑比较简单了,如果将Timer加到NSDefaultRunLoopMode模式下,哪么当scrollView滚动的时候,会导致Timer失效。解决方法比较简单,就是将Timer加到NSRunLoopCommonModes模式下,这样就确保了Timer不会失效