如何在Objective-C/iOS中创建准确的计时器事件?

Mic*_*own 5 timer objective-c nstimer ios

我想在iOS上为SMPTE时间码(HH:MM:SS:FF)创建一个倒数计时器.基本上,它只是一个倒数计时器,分辨率为33.33333ms.我不太确定NSTimer的准确性足以引发事件来创建这个计时器.每次此计时器递增/递减时,我想触发一个事件或调用一段代码.

我是Objective-C的新手,所以我正在寻找社区的智慧.有人建议使用CADisplayLink类,寻找一些专家建议.

Jod*_*ins 13

试试CADisplayLink.它以刷新率(60 fps)触发.

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

这将每2帧发射一次,即每秒30次,这似乎就是你所追求的.

请注意,这与视频帧处理有关,因此您需要非常快速地在回调中完成工作.


ben*_*ado 5

基本上,你有或者没有保证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;
}
Run Code Online (Sandbox Code Playgroud)

现在,无论定时器触发的频率如何,您都将显示正确的时间码.(如果计时器不经常启动,计时器将不会更新,但是当它更新时它将是准确的.它永远不会失去同步.)

如果使用CADisplayLink,则会在显示更新时调用您的方法.换句话说,尽可能快,但不会更快.如果您正在显示时间,那可能就是要走的路.