1、创建
(1.1)timerWithTimeInterval 创建
在调用 fire 方法后唤醒开始运行。
self.timer = [NSTimer timerWithTimeInterval:2 repeats:true block:^(NSTimer * _Nonnull timer)
NSLog(@"timer");
}];
[self.timer fire];
(1.2)scheduledTimerWithTimeInterval 创建
创建后立刻唤醒开始运行。
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(method) userInfo:nil repeats:YES];
2、控制
(2.1)暂停
原理:触发时间设置在未来
[self.timer setFireDate:[NSDate distantFuture]];
(2.2)继续 / 开始
原理:触发时间设置在现在
[self.timer setFireDate:[NSDate date]];
(2.3)停止
原理:停止定时器
[self.timer invalidate];
3、关于 Runloop 切换场景
(3.1)关于被 Runloop 持有
NSTimer 会被添加在所在线程的 Runloop 中,而 Runloop 对 Timer 是一种强持有关系。为什么呢?
(1)RunLoop 有一个基于时间的触发器的类,CFRunLoopTimerRef,和 NSTimer 是 toll-free bridged 的桥接对应关系。
(2)CFRunLoopTimerRef 包含 时间长度、回调(函数指针)
(3)当 NSTimer 加入到 RunLoop 时,RunLoop 会注册对应的时间点,当时间点到达时,RunLoop 会被唤醒,以执行那个回调。
(3.2)关于默认运行 Mode
NSTimer 默认是被加入到了 kCFRunLoopDefaultMode
所以当 Runloop 的 Mode 变化时,当前的 NSTimer 就不会工作了。
场景:
当滑动 TableView 时,RunLoop 切换到 UITrackingRunLoopMode。
而 NSTimer 是在 kCFRunLoopDefaultMode下的,就无法接受处理 Timer 的事件。此时 Timer 的事件将不会被触发调用。
如何解决:
(1)将 Timer 添加到 UITrackingRunLoopMode —— 不行,因默认情况下则不运行。
(2)将 Timer 同时添加到 UITrackingRunLoopMode 和 kCFRunLoopDefaultMode 上 —— 默认情况、滑动ScrollerView时,均能运行。
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(method) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
Timer 则被添加到多个mode上。
(3)使用 GCD 定时器。
网友评论