NSTimer在被解雇之前开火

时间:2016-04-20 12:59:47

标签: ios swift nstimer

我有以下代码,它根据存储在NSDefault变量checkOutTime中的值初始化NSTimer。

假设我将此变量中的时间更改为过去时间(当前时间之前)并重新初始化计时器,则会自动触发并调用ForceCheckOut()回调方法。

我需要计时器才能在给定的开火日期开火。

func InitilizeAutoCheckOut(isExtendedCheckout:Bool)
{

        let checkOutTime = self.defaults.valueForKey("checkOutTime") as! String

        print(checkOutTime)



        if !checkOutTime.isEmpty
        {
            let date = self.StringToDate(checkOutTime, IsExtendedCheckout: isExtendedCheckout)

            print(date)

            let autoCheckOutTimer = NSTimer(fireDate: date, interval: 24*60*60, target: self, selector: #selector(DashboardViewController.ForceCheckOut), userInfo: nil, repeats: true)
            NSRunLoop.mainRunLoop().addTimer(autoCheckOutTimer, forMode: NSDefaultRunLoopMode)

        }

}

1 个答案:

答案 0 :(得分:2)

正如在几个地方(here is a good example)中所解释的那样,NSTimer&#39; fireDate实际上并不是计时器触发的日历日期时间。将其视为要求倒计时的机制更为准确。值得注意的是,NSTimer并不考虑时钟重置,后台处理等。它基本上计算一个数字,直到它应该触发,定期递减该数字,然后触发一次该数字<= 0更改本地时钟不会影响该号码,暂停该过程(例如,通过后台应用程序)将导致倒计时从其当前值恢复,而不考虑其睡眠时间。这可以说是非直观的,因为fireDate强烈暗示了在这个日历日期&#34;触发的合同,但API就是它。

有了这些知识,你可以直觉意识到你所看到的行为是预期的:如果你过去设定了一个日期,你实际上是要求计时器从(负数)倒计时,所以计时器立即识别出它的火情已经满足(剩余时间<= 0),并且一旦它被跑声吵醒就会开火。

但即使没有这方面的知识,我也会认为这种行为满足的期望远远超过它的预期。考虑:

  

无论[公差]的值如何,系统都保留对某些计时器应用少量公差的权利。 - NSTimer class ref

如果您将来安排一个非常短暂的计时器,那么在计划的时间实际通过之前,计时器可能不会被runloop检查。即使时间过去,通过触发计时器,计时器会在指定时间或多或少地触发,从而满足程序员的期望。

此外,您所期望的行为会引发围绕管理计时器的一系列复杂情况。如果您将来创建一个具有开火日期的计时器,但是在该开火日期过去之前不要添加它,该怎么办?定时器是否会起火?目前的行为避免了这一决定。

最简单的解决方案可能是在安排计时器之前检查开火日期,如果开火日期符合您的条件,则只将其添加到运行循环中:

let date = self.StringToDate(checkOutTime, IsExtendedCheckout: isExtendedCheckout)
let comparison = date.compare(NSDate())
guard comparison != .OrderedAscending else {
    print("date \(date) has already passed. Not scheduling timer.")
    return
}