突然有个疑问: 在一个子线程中启动一个timer,但是不添加到Runloop中,调用timer.fire(),这时候timer 会运行吗?
实践出真知 😝
var times = 1;
let thread = Thread {
let timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
print("repeating \(Date.init()) times = \(times)")
if(times < 20){
times += 1
}else{
timer.invalidate()
}
})
timer.fire()
//RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
print(timer.fireDate)
RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop运行后 在10s 后退出
//RunLoop.current.run(until: Date.distantFuture)
print(timer.fireDate)
}
print("1 \(thread.isExecuting)")
thread.start()
print("2 \(thread.isExecuting)")
let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
DispatchQueue.global().asyncAfter(deadline:disTime) {
print("3 \(thread.isExecuting)")
print(thread)
print(Thread.current)
}
输出结果是:
1 false
2 false
repeating 2017-03-26 02:38:35 +0000 times = 1
2017-03-26 02:38:36 +0000
2017-03-26 02:38:36 +0000
3 false
<NSThread: 0x60000026f740>{number = 3, name = (null)}
<NSThread: 0x600000271b00>{number = 4, name = (null)}
在没有将timer add 到Runloop 中&& runloop 停止之前, timer 仅仅触发了一次执行操作。
WHY ?
到底这个timer 在线程中一直执行没有呢?很显然,他就执行一次(这与RunLoop 有何关系?)
那是不是Timer 执行完就被释放了呢,我们再看看3s 后 这个timer 是否还有效,times < 2
, 添加3s 后检查timer.isvalide
var times = 1;
let thread = Thread {
let timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
print("repeating \(Date.init()) times = \(times)")
if(times < 2){
times += 1
}else{
timer.invalidate()
}
})
timer.fire()
//RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
print(timer.fireDate)
RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop运行后 在10s 后退出
//RunLoop.current.run(until: Date.distantFuture)
print(timer.fireDate)
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(3), execute: {
print("after 3s timer is running \(timer.isValid )")
})
}
print("1 \(thread.isExecuting)")
thread.start()
print("2 \(thread.isExecuting)")
let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
DispatchQueue.global().asyncAfter(deadline:disTime) {
print("3 \(thread.isExecuting)")
print(thread)
print(Thread.current)
}
在看输出:
1 false
2 true
repeating 2017-03-26 03:01:41 +0000 times = 1
2017-03-26 03:01:42 +0000
2017-03-26 03:01:42 +0000
after 3s timer is running true
3 false
<NSThread: 0x60000007f100>{number = 3, name = (null)}
<NSThread: 0x600000261900>{number = 4, name = (null)}
我认为 timer 就是一个线程,没有将其加入到Runloop ,该timer执行完他的代码就退出了。
可是线程要Runloop 干嘛呢?不是没有runLoop 线程也可以执行吗?确实是。
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出
CFRunLoopTimerRef 是基于时间的触发器,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop会注册对应的时间点,当时间点到时,RunLoop会被唤醒以执行那个回调。
根据这个说法那就不难理解,如果不添加到Runloop ,Runloop 没有可接收的消息源,所在线程执行完后就退出。
一般滑动列表的时候我们还有一个timer 在运行,发现Timer 的回调不执行。原因有二
- 滑动列表是在TrackingMode,Timer 在defaultMode
- 同一时刻Runloop只对应一个Mode
从timer 的mode 切换到 trackingMode,Timer 的回调不执行,但是再次执行的时候会顺延至指定的间隔的整数倍(比如我们4:10 开启,每隔1m 调用一次,在4:12 切换到TrackingMode 4 m 后再切回来,那下次启动大概就是4:17 左右开始回调执行)
参考
Runloop的add 方法
func add(_ timer: Timer, forMode mode: RunLoopMode)
Description
Registers a given timer with a given input mode.
You can add a timer to multiple input modes. While running in the designated mode, the receiver causes the timer to fire on or after its scheduled fire date. Upon firing, the timer invokes its associated handler routine, which is a selector on a designated object.
The receiver retains aTimer. To remove a timer from all run loop modes on which it is installed, send an invalidate() message to the timer.
网友评论