2011-10-06 94 views
4

我正在使用NSTimer來更新顯示每分鐘當前時間的標籤。我在一個完整的分鐘日期(例如2:23:00而不是2:22:17)啓動計時器。問題是NSTimer似乎工作不正確,這意味着它有時會引發太早(導致(例如)2:23 PM,實際上是2:24 PM)。NSTimer不準確?

是否有任何修復/解決方法?

編輯:這就是我如何啓動定時器:

NSTimer *clockTimer = [[NSTimer alloc] initWithFireDate:[NSDate nextFullMinuteDate] 
               interval:60.0 
               target:self 
               selector:@selector(updateClocks:) 
               userInfo:nil 
               repeats:YES]; 
[[NSRunLoop currentRunLoop] addTimer:clockTimer 
          forMode:NSDefaultRunLoopMode]; 
[clockTimer release]; 

順便說一句,我曾嘗試加入幾毫秒到火日期,這似乎幫助,但它看起來就像找到被擊中適當的間隔添加-and錯過。編輯2:好吧,所以我手動設置我的計時器在一分鐘後0.05秒發射,然後在60.0秒後再次發射。現在,這裏是我在調用的方法登錄:

0.048728 
0.047153 
0.046484 
0.044883 
0.043103 

正如你所看到的,NSTimer實際上並未使用60秒的時間間隔,但略短的一個。

+0

很難說不知道如何計算間隔並啓動計時器 – hamstergene

+0

如何計算'nextFullMinuteDate'? –

+0

@PeterHosey:look [here](http://pastebin.com/ZsXWfM0p) – ryyst

回答

0

那麼,我只是寫了我自己的小NSTimer包裝,叫做MinuteTimer來「解決」這個問題。我上傳了pastebin。這個想法是重置定時器,只要它經常發射得太快以至於日期風險顯示不正確。

由於這是管道式磁帶編程,我仍然渴望聽到其他答案!

0

我假設你從當前時間開始,然後每當NSTimer關閉時,你將一分鐘添加到原始時間,然後顯示它。你應該對你的計時器做什麼:每當計時器關閉時,重新讀取當前時間並顯示它。

+0

不,我總是重讀當前時間並顯示它。 – ryyst

+0

您還應該每分鐘更頻繁地啓動計時器。 – MusiGenesis

+0

因爲計時器似乎太早啓動。像在2:23:59.999而不是2:24:00。至少這是我認爲正在發生的事情。 – ryyst

0

您應該將您的計時器設置爲每秒鐘而不是每分鐘。但不要每秒更新你的標籤。只需比較當前時間的新分鐘數是否與上次更新標籤的分鐘數不同,如果是,則更新標籤。

+1

對不起,但這聽起來效率很低。 – ryyst

1

NSTimer docs

計時器不是實時的機構;只有在添加了定時器的 運行循環模式之一運行並且能夠 檢查定時器的觸發時間是否已經過去時纔會觸發。由於典型的運行循環管理各種輸入源,所以有效的分辨率爲 ,定時器的時間間隔被限制在大約50-10 毫秒的量級。如果在長時間標註或 期間發生定時器的觸發時間,而運行循環處於未監控定時器的模式,則在下一次運行循環檢查定時器之前,定時器不會觸發。因此,計時器觸發的實際時間可以在預定的觸發時間之後的相當長的一段時間內爲 。

這意味着NSTimer是非常不準確的。

如果您編寫「秒錶」,則可以使用NSTimer向用戶顯示結果,而NIRTimer(我最喜歡的類之一)會記錄時間。此概述如下:

NIRTimer *nirTimer; 
NSTimer *timer; 

- (void)start { 
    nirTimer = [[NIRTimer alloc]init]; 
    timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES]; 
    [nirTimer start]; 

- (void)timerFired:(NSTimer *)timer { 
    [self displayTimeToUser:[nirTimer seconds]]; 
} 

在上面的代碼中,NSTimer可能不準確,但是精確的時間由NIRTimer,其每0.01秒顯示給用戶保持。

如果你確實需要特定的代碼運行在一個確切的時間,我已經找到了最好的解決方案是使用NSThreadusleep()

BOOL timerRunning; 

- (void)start { 
    timerRunning = YES; 
    [NSThread detachNewThreadSelector:@selector(timer) toTarget:self withObject:nil]; //make a new thread 
} 

- (void)timer { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init]; //Make an autorelease pool since we're in a new thread 
    NIRTimer *timer = [[NIRTimer alloc]init]; //Make an NIRTimer 
    while (timerRunning) { 
     [timer reset]; 
     [timer start]; 
     [self doSomething]; 
     usleep(10000 - [timer microseconds]); //Wait for .01 seconds which is 10000 microseconds (a microsecond is 1/1000000th of a second) - the time it took to accomplish whatever we were doing 
    } 
    //Clean up 
    [timer release]; 
    [pool release]; 
} 

在這種情況下,設置timerRunningNO停止定時器。如果您嘗試執行的操作不是線程安全的,您可能還想使用[self performSelectorOnMainThread:@selector(doSomething) withObject:nil waitUntilDone:NO]而不是[self doSomething]

欲瞭解更多精彩的穿線世界,請看Threading Programming Guide