2010-01-03 41 views
22

我剛剛完成了我的應用程序和beta版測試,發現了一個在秒錶部分的錯誤... 秒錶使用nstimer來進行計數並有一個表來存儲圈數,但是當捲動表滾動時,手錶停止或暫停,並且不彌補失去的時間。NSTimer在runloop被阻止時沒有觸發

這被拖延被淘汰使用:

startingTime = [[NSDate date] timeIntervalSince1970]; 

來計算所經過的時間。

但我仍然在使用NSTimer觸發每隔0.1秒,這意味着即使經過的時間將在最後正確更新,滾動仍然停滯計時器...並將其與蘋果計時器進行比較我想知道那個秒錶是否有一個單獨的線程來計算經過的時間。有誰知道這是如何完成的?

現在,使用從紀元在某種意義上是運作良好的時間,但它啓動,停止,&重新啓動秒錶

當手錶停止時存儲的時間和用於計算的事情複雜化手錶重新啓動時的偏移量,但似乎引入了一些延遲,並且在重新啓動手錶時,時間會明顯向前跳躍。

任何想法的根本原因或解決方案將不勝感激。

回答

22

如果事件循環沒有運行,任何定時器都不會觸發,直到事件循環再次運行。即使事件循環不是阻塞狀態,定時器也不能保證以確切的配置間隔觸發。如果您的時間完全基於定時器開火,則錯誤量將隨着時間而增加。

您需要跟蹤定時器觸發的持續時間。每次定時器啓動時,重新計算您的持續時間並重新顯示。

一開始/暫停/重新啓動/停止設置的類型,則通常要:

  • 搶時間啓動時(無論是作爲一個NSDate實例或作爲NSTimeInterval值)

  • 暫停或停止時,暫停/停止時抓住時間。從這個時間減去開始時間和你有時間間隔的時間

  • 在重新啓動時,在重新啓動時搶時間,而且還保持周圍已經經過的持續時間

  • 在暫停/停止,搶時間暫停/停止和添加已經經過的持續時間

一般來說,做這一切與NSTimeInterval值 - 這只是雙打 - 是最容易。但是,如果需要跟蹤事件發生時的實際時間,請改爲使用NSDate實例。

46

bbum的答案提供了一種設計應用程序的更好方法,但是如果您希望計時器觸發而不管用戶是否在操作UI,則需要將其添加到runloop的跟蹤模式。

假設您正在開發iPhone,該模式爲UITrackingRunLoopMode。如果您正在爲Mac開發,則會有一個類似的名稱爲NSEventTrackingRunLoopMode

NSRunLoop *runloop = [NSRunLoop currentRunLoop]; 
NSTimer *timer = [NSTimer timerWithTimeInterval:0.1 target:self selector:@selector(myTimerAction:) userInfo:nil repeats:YES]; 
[runloop addTimer:timer forMode:NSRunLoopCommonModes]; 
[runloop addTimer:timer forMode:UITrackingRunLoopMode]; 
+1

這仍然不能保證整體計時的準確性。定時器不能保證以完全配置的時間間隔觸發。更糟糕的是,如果每個定時器觸發都會增加整個時間間隔,每次定時器觸發時錯誤的數量都會增加! – bbum 2010-01-04 01:06:04

+0

我並不打算爭辯說,除了定時器會在控件跟蹤時觸發外,他們會保證其他任何東西。在圈速開始時存儲日期並使用它來計算運行時間比您的答案中所陳述的準確得多(並且更簡單的IMO)。 – 2010-01-05 00:06:40

+0

+1爲我工作。 bbum的回答對我沒有任何意義。 – bentford 2011-07-30 22:17:51