如何创建在Objective-C / iOS的一个精确的定时器事件?(How do I create

2019-07-29 12:44发布

我期待创造SMPTE时间码(HH:MM:SS:FF)倒数计时器在iOS上。 基本上,它只是与33.33333ms分辨率的倒数计时器。 我不是很确定的NSTimer是精确到足以算的上触发事件来创建此计时器。 我想触发一个事件或每隔该定时器递增/递减时间打电话的一段代码。

我是新来的Objective-C,所以我正在寻找来自民间智慧。 有人建议CADisplayLink类,寻找一些专家的意见。

Answer 1:

尝试CADisplayLink。 它火的刷新速率(每秒60帧)。

CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(timerFired:)];
displayLink.frameInterval = 2;
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

这将触发每2帧,也就是每秒30次,这似乎是你所追求的。

请注意,这是依赖于视频帧处理,所以你需要非常迅速地做你的回调的工作。



Answer 2:

基本上,你有或者没有担保NSTimerdispatch_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,你的方法被称为显示器的更新速度。 换句话说,以最快的速度将是有益的,但没有速度更快。 如果你显示的时间,这可能是要走的路。



Answer 3:

如果你的目标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(); 当你要开始计时。 对于重复的循环,我个人认为这是比上面的块的方法干净了一点,但对于一次性的任务,我肯定更喜欢块方法。

见大中央调度文档获取更多信息。



文章来源: How do I create an accurate timer event in Objective-C/iOS?