为什么定时器有时会这么快地调用它的块
Why timer invoke its block so quickly sometimes
我创建了一个计时器并每 5 秒调用一次它的块。然后我申请进入后台并在一段时间后进入前台。但它有时可以快速调用块。
let _ = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { (timer) in
print("--------")
}
当我进入前台时,有时第一次打印和第二次打印的间隔可能不到一秒。在这种情况下时间间隔是否无效?
当应用程序进入后台时,应用程序会很快挂起,程序停止运行。当应用程序切换回前台时,将触发 buffered/delayed 计时器事件,然后您很快就会看到许多打印件。
要了解该行为,您需要了解 NSTimer
和 RunLoop
的工作原理。简单来说,RunLoop
会检查 Timer 是否应该触发,如果是,它会通知 Timer 触发选择器,否则它不会。现在,由于您在后台,您的 RunLoop
不会检查事件,因此它无法通知计时器。但是一旦它进入前台,它会发现即使它通过了 fireDate 也需要通知 Timer。
时间线图:
设 A(第 5 秒)和 B(第 10 秒)为定时器触发事件。安排在计时器上 Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true)
C进入后台(0秒)
D 将回到前台(第 9 秒,在 A 和 B 之间)。
-----> A ------> B
C--------->D
解释:
在 C 上,RunLoop 将暂停。因此,在 RunLoop 恢复处理之前无法处理事件 A,这是在事件 D 上。在事件 D 上,它将看到事件 A 应该触发,因此它会通知计时器。一秒钟后,RunLoop 会看到事件 B 已经发生,因此它会再次通知 Timer。此场景解释了为什么您的事件以秒为间隔打印。只是延迟的事件处理让它看起来更早触发,而实际上它处理得晚。
Apple 文档:
A timer is not a real-time mechanism. If a timer’s firing time occurs
during a long run loop callout or while the run loop is in a mode that
isn't monitoring the timer, the timer doesn't fire until the next time
the run loop checks the timer. Therefore, the actual time at which a
timer fires can be significantly later.
资源:、NSRunLoop 和定时器文档
建议:
应用程序进入后台后停止计时器,但存储 fireDate
。回到前台后,检查 fireDate
是否超过 Date()
。然后在前台创建一个新的定时器来处理事件。
我创建了一个计时器并每 5 秒调用一次它的块。然后我申请进入后台并在一段时间后进入前台。但它有时可以快速调用块。
let _ = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { (timer) in
print("--------")
}
当我进入前台时,有时第一次打印和第二次打印的间隔可能不到一秒。在这种情况下时间间隔是否无效?
当应用程序进入后台时,应用程序会很快挂起,程序停止运行。当应用程序切换回前台时,将触发 buffered/delayed 计时器事件,然后您很快就会看到许多打印件。
要了解该行为,您需要了解 NSTimer
和 RunLoop
的工作原理。简单来说,RunLoop
会检查 Timer 是否应该触发,如果是,它会通知 Timer 触发选择器,否则它不会。现在,由于您在后台,您的 RunLoop
不会检查事件,因此它无法通知计时器。但是一旦它进入前台,它会发现即使它通过了 fireDate 也需要通知 Timer。
时间线图:
设 A(第 5 秒)和 B(第 10 秒)为定时器触发事件。安排在计时器上 Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true)
C进入后台(0秒)
D 将回到前台(第 9 秒,在 A 和 B 之间)。
-----> A ------> B
C--------->D
解释:
在 C 上,RunLoop 将暂停。因此,在 RunLoop 恢复处理之前无法处理事件 A,这是在事件 D 上。在事件 D 上,它将看到事件 A 应该触发,因此它会通知计时器。一秒钟后,RunLoop 会看到事件 B 已经发生,因此它会再次通知 Timer。此场景解释了为什么您的事件以秒为间隔打印。只是延迟的事件处理让它看起来更早触发,而实际上它处理得晚。
Apple 文档:
A timer is not a real-time mechanism. If a timer’s firing time occurs during a long run loop callout or while the run loop is in a mode that isn't monitoring the timer, the timer doesn't fire until the next time the run loop checks the timer. Therefore, the actual time at which a timer fires can be significantly later.
资源:
建议:
应用程序进入后台后停止计时器,但存储 fireDate
。回到前台后,检查 fireDate
是否超过 Date()
。然后在前台创建一个新的定时器来处理事件。