7

我想實現一個基於MVC模型的秒錶。秒錶的觀察者模式

秒錶使用NSTimer,並在每次超時時調用選擇器-(void) tick

我試圖讓秒錶作爲可重用性的模型,但我遇到了一些關於如何更新每個刻度的視圖控制器的設計問題。

首先我使用tick方法創建了一個協議,並將視圖控制器作爲其委託。然後視圖控制器根據每個滴答的計時器屬性更新視圖。 elapsedTime是隻讀NSTimeInterval。

它的工作原理,但我認爲這可能是不好的設計。我是Objective-C/Cocoa Touch初學者。我應該使用類似KVO的東西嗎?或者有沒有更適合模型的解決方案,以通知視圖控制器elapsedTime已更改?

+1

第一個問題很好!歡迎來到SO! –

+0

定時器和視圖控制器之間的關係究竟是什麼?計時器是否由VC擁有? –

+0

謝謝:) 計時器是由VC所有,是的。我已經實現了一個從Timer繼承的IntervalTimer,然後VC擁有IntervalTimer,IntervalTimer實際上是給我一些麻煩的一個。 – Jach0

回答

0

最近,我一直在使用塊而不是普通的舊@selector's。它創建更好的代碼並將邏輯保持在同一位置。

有沒有原生塊NSTimer支持,但我用從https://gist.github.com/250662/d4f99aa9bde841107622c5a239e0fc6fa37cb179

類別沒有回報選擇,你保持代碼在一個地方:

__block int seconds = 0; 
    NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:1 
               repeats:YES 
               usingBlock:^(NSTimer *timer) { 

               seconds++; 
               // Update UI 

               if (seconds>=60*60*2) { 
                [timer invalidate]; 
               } 




}]; 
5

定時器是一個好辦法確保你定期更新你的用戶界面,但不要用它來記錄時間。 NSTimer can drift,如果您使用計時器來累計秒數,任何小錯誤都可能累積。

相反,使用NSTimer觸發更新您的UI的方法,但使用NSDate獲得實時。 NSDate會給你毫秒分辨率;如果你真的需要比這更好的話,請考慮this suggestion to use Mach's timing functions。因此,使用NSDate的,你的代碼可能是這樣的:

- (IBAction)startStopwatch:(id)sender 
{ 
    self.startTime = [NSDate date]; 
    self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1 
                target:self 
               selector:@selector(tick:) 
               userInfo:repeats:YES]; 
} 

- (void)tick:(NSTimer*)theTimer 
{ 
    self.elapsedTime = [self.startTime timeIntervalSinceNow]; 
    [self updateDisplay]; 
} 

- (IBAction)stopStopwatch:(id)sender 
{ 
    [self.timer invalidate]; 
    self.timer = nil; 
    self.elapsedTime = [self.startTime timeIntervalSinceNow]; 
    [self updateDisplay]; 
} 

如果允許重新啓動,等你的代碼可能會有點更復雜,但這裏最重要的是,你不使用的NSTimer來測量總經過時間。

您可以在this SO thread中找到其他有用的信息。

2

我會建議針對這個問題的KVO。它在這裏引入了很多複雜性(和幾個令人討厭的陷阱),對此沒有多大的益處。 KVO在需要確保最小開銷的情況下非常重要。 Apple在低層次,高性能對象(如圖層)中使用它很多。當沒有觀察者時,它是唯一通用的解決方案,可以提供零開銷。大多數情況下,你不需要這些。正確處理KVO可能會很棘手,而且它可以創建的錯誤令人討厭追蹤。

您的委託方法沒有任何問題。這是正確的MVC。你唯一需要擔心的是NSTimer沒有對它被叫的時間作出強有力的承諾。在某些情況下,重複計時器甚至可以跳過。爲了避免這個問題,您通常需要根據當前時間計算elapsedTime,而不是增加它。如果計時器可以暫停,那麼你需要保留一個累加器和一個「我上次開始的時間」的日期。

如果需要更高的精度和成本較低的定時器,你可以看看dispatch_source_set_timer(),但對於一個簡單的人,有針對性的秒錶,NSTimer是罰款,並作一個簡單的項目的最佳選擇。

+0

我知道跳過計時器和使用增量的問題。我使用NSDate和setElapsedTime我比較NSDates(+使用暫停時的偏移量) – Jach0

+0

我試圖實現一個間隔倒數計時器,該計時器從秒錶繼承並具有一些額外的屬性,包括workInterval和restInterval,但標籤在我的ViewController get的更新有點奇怪。我認爲這可能與ViewController的tick,Timers tick和IntervalTimers tick之間的順序調用有關。 – Jach0