秒表的观察者模式
我想实现一个基于MVC模型的秒表。秒表的观察者模式
秒表使用NSTimer,并在每次超时时调用选择器-(void) tick
。
我试图让秒表作为可重用性的模型,但我遇到了一些关于如何更新每个刻度的视图控制器的设计问题。
首先我使用tick方法创建了一个协议,并将视图控制器作为其委托。然后视图控制器根据每个滴答的计时器属性更新视图。 elapsedTime是只读NSTimeInterval。
它的工作原理,但我认为这可能是不好的设计。我是Objective-C/Cocoa Touch初学者。我应该使用类似KVO的东西吗?或者有没有更适合模型的解决方案,以通知视图控制器elapsedTime
已更改?
最近,我一直在使用块而不是普通的旧@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];
}
}];
定时器是一个好办法确保你定期更新你的用户界面,但不要用它来记录时间。 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中找到其他有用的信息。
我会建议针对这个问题的KVO。它在这里引入了很多复杂性(和几个令人讨厌的陷阱),对此没有多大的益处。 KVO在需要确保最小开销的情况下非常重要。 Apple在低层次,高性能对象(如图层)中使用它很多。当没有观察者时,它是唯一通用的解决方案,可以提供零开销。大多数情况下,你不需要这些。正确处理KVO可能会很棘手,而且它可以创建的错误令人讨厌追踪。
您的委托方法没有任何问题。这是正确的MVC。你唯一需要担心的是NSTimer没有对它被叫的时间作出强有力的承诺。在某些情况下,重复计时器甚至可以跳过。为了避免这个问题,您通常需要根据当前时间计算elapsedTime
,而不是增加它。如果计时器可以暂停,那么你需要保留一个累加器和一个“我上次开始的时间”的日期。
如果需要更高的精度和成本较低的定时器,你可以看看dispatch_source_set_timer()
,但对于一个简单的人,有针对性的秒表,NSTimer
是罚款,并作一个简单的项目的最佳选择。
第一个问题很好!欢迎来到SO! –
定时器和视图控制器之间的关系究竟是什么?计时器是否由VC拥有? –
谢谢:) 计时器是由VC所有,是的。我已经实现了一个从Timer继承的IntervalTimer,然后VC拥有IntervalTimer,IntervalTimer实际上是给我一些麻烦的一个。 – Jach0