为什么计时器有时会这么快地调用其块

时间:2018-12-05 02:33:28

标签: ios nstimer

我创建一个计时器,每5秒钟调用一次它的块。然后我让应用程序进入背景,过一会儿进入前景。但是有时它可以快速调用该块。

let _ = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { (timer) in
        print("--------")
   }

当我进入前景时,第一次打印和第二次打印的间隔有时会小于一秒。在这种情况下时间间隔无效吗?

2 个答案:

答案 0 :(得分:2)

要了解此行为,您需要了解NSTimerRunLoop的工作方式。简单来说,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恢复对事件D的处理后,才可以处理事件A。在事件D上,它将看到事件A应该触发,以便通知计时器。一秒钟后,RunLoop将看到事件B已经发生,因此它将再次通知计时器。这种情况说明了为什么您的事件每隔一秒就会打印一次。只是延迟的事件处理使它似乎早于触发,而实际上却被延迟处理了。

Apple Doc:

  

计时器不是实时机制。如果发生计时器的触发时间   在长时间运行的循环标注中或运行循环处于以下模式时   没有监控计时器,直到下一次计时器才会启动   运行循环检查计时器。因此,实际时间   定时器触发可能要晚得多。

资源:What is an NSTimer's behavior when the app is backgrounded?,NSRunLoop和Timer Docs

建议:

一旦应用程序进入后台,请停止计时器,但要存储fireDate。回到前台后,检查fireDate是否超过Date()。然后创建一个新的Timer来处理前台事件。

答案 1 :(得分:1)

当应用程序进入后台时,该应用程序将很快挂起,程序停止运行。当应用切换回前台时,将触发缓冲/延迟计时器事件,然后您会很快看到许多打印内容。