2016-04-20 117 views
1

我有下面的代碼根據存儲在NSDefault變量checkOutTime中的值初始化NSTimer。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) 

     } 

} 
+0

檢查時區爲系統時區與否。 –

回答

2

正如在幾個地方(here is a good example)解釋說,NSTimerfireDate實際上不是一個日曆日期時間在該定時器觸發。把它想象成一個要求倒計時的機制更準確。值得注意的是,NSTimer不考慮時鐘重置,背景等。它基本上計算一個數字直到它應該觸發,週期性地減少該數字,並且一旦該數字觸發該數字< = 0。改變本地時鐘不影響該數字,並且暫停該過程(例如,通過後臺應用程序)將導致倒計時從其當前值恢復,而不考慮它睡着的時間。這可以說是不直觀的,因爲fireDate強烈暗示着「在這個日曆日期發生火災」的合約,但API是它的原型。

有了這些知識,你可以憑直覺,你所看到的行爲是正常的:如果設置在過去的日期,你基本上要求計時器從(負數)倒數,所以計時器立即認識到它的火情已經滿足(剩餘時間< = 0),一旦它被runloop喚醒就會觸發。

但即使沒有這方面的知識,我也會認爲這種行爲滿足了更多的期望。考慮:

無論[tolerance]的值如何,系統保留對某些定時器應用少量容差的權利。 - 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 
}