我期待创造SMPTE时间码(HH:MM:SS:FF)倒数计时器在iOS上。 基本上,它只是与33.33333ms分辨率的倒数计时器。 我不是很确定的NSTimer是精确到足以算的上触发事件来创建此计时器。 我想触发一个事件或每隔该定时器递增/递减时间打电话的一段代码。
我是新来的Objective-C,所以我正在寻找来自民间智慧。 有人建议CADisplayLink类,寻找一些专家的意见。
我期待创造SMPTE时间码(HH:MM:SS:FF)倒数计时器在iOS上。 基本上,它只是与33.33333ms分辨率的倒数计时器。 我不是很确定的NSTimer是精确到足以算的上触发事件来创建此计时器。 我想触发一个事件或每隔该定时器递增/递减时间打电话的一段代码。
我是新来的Objective-C,所以我正在寻找来自民间智慧。 有人建议CADisplayLink类,寻找一些专家的意见。
尝试CADisplayLink。 它火的刷新速率(每秒60帧)。
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(timerFired:)];
displayLink.frameInterval = 2;
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
这将触发每2帧,也就是每秒30次,这似乎是你所追求的。
请注意,这是依赖于视频帧处理,所以你需要非常迅速地做你的回调的工作。
基本上,你有或者没有担保NSTimer
或dispatch_after
; 他们调度代码以触发主线上,但如果别的东西需要很长的时间来执行,并阻止主线程,你的计时器就不会触发。
这就是说,你可以很容易地避免阻塞主线程(仅使用异步I / O)和事情应该是相当不错的。
你不说正是你所需要的计时器代码来完成,但是如果你需要做的是显示一个倒计时,你应该罚款,只要你计算基础上的系统时间的SMPTE时间,而不是数你想秒应根据您的计时器间隔已过去。 如果你这样做,你几乎肯定会漂移,不同步的实际时间。 相反,注意你的起始时间,然后以此为基础进行的所有数学:
// Setup
timerStartDate = [[NSDate alloc] init];
[NSTimer scheduledTimer...
- (void)timerDidFire:(NSTimer *)timer
{
NSTImeInterval elapsed = [timerStartDate timeIntervalSinceNow];
NSString *smtpeCode = [self formatSMTPEFromMilliseconds:elapsed];
self.label.text = smtpeCode;
}
现在你无论定时器的频率发射显示正确的时间码。 (如果计时器不火往往不够,定时器将不会更新,但是当它更新这将是准确的。它永远不会得到不同步。)
如果你使用CADisplayLink,你的方法被称为显示器的更新速度。 换句话说,以最快的速度将是有益的,但没有速度更快。 如果你显示的时间,这可能是要走的路。
如果你的目标iOS 4以上版本,可以使用大中央调度:
// Set the time, '33333333' nanoseconds in the future (33.333333ms)
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 33333333);
// Schedule our code to run
dispatch_after(time, dispatch_get_main_queue(), ^{
// your code to run here...
});
这将33.333333ms后调用该代码。 如果这将是一个循环八九不离十交易,你可能想使用dispatch_after_f
函数而不是使用函数指针,而不是块:
void DoWork(void *context);
void ScheduleWork() {
// Set the time, '33333333' nanoseconds in the future (33.333333ms)
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 33333333);
// Schedule our 'DoWork' function to run
// Here I pass in NULL for the 'context', whatever you set that to will
// get passed to the DoWork function
dispatch_after_f(time, dispatch_get_main_queue(), NULL, &DoWork);
}
void DoWork(void *context) {
// ...
// Do your work here, updating an on screen counter or something
// ...
// Schedule our DoWork function again, maybe add an if statement
// so it eventually stops
ScheduleWork();
}
然后,只需调用ScheduleWork();
当你要开始计时。 对于重复的循环,我个人认为这是比上面的块的方法干净了一点,但对于一次性的任务,我肯定更喜欢块方法。
见大中央调度文档获取更多信息。