English 中文(简体)
如何在目标C/iOS中创造准确的计时事件?
原标题:How do I create an accurate timer event in Objective-C/iOS?

我期待在iOS上为 SMPTE 时间代码( HH: MM:SS:FF) 创建一个倒计时计时器。 基本上, 它只是一个计时计时器, 分辨率为33.33333米。 我不确定NSTimer 是否准确到可以计算到点火事件来创建这个计时器。 我想每次计时器加分/ 降时都会点出一个事件或调用一个代码 。

我新到目标C,所以我从社区寻求智慧。有人建议CA DisplayLink 课程,寻找一些专家意见。

最佳回答

尝试 CA DisplayLink 。 它以更新速率( 60 fps) 开火 。

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

每2个框架,每秒发射30次, 这似乎是你所追求的。

注意, 这是与视频框架处理有关的, 所以您需要尽快在回调中完成您的工作 。

问题回答

您基本上没有保证 NSTimerr 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;
}

现在您将显示正确的时间代码, 不论何时该计时器被发射。 (如果计时器不经常发射, 计时器将无法更新, 但当它更新时它会准确。 它永远不会脱离同步 。)

如果您使用 CA DisplayLink, 您的方法将会被调用与显示更新一样快。 换句话说, 您的方法会被调用得越快, 越快越有用, 但不能再快。 如果您重新显示时间, 那可能就是前进的方向 。

如果您正在瞄准 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 之后调用该代码。 如果这是环排序交易, 您可能想要使用 < code> dispatch_ faf_ 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();
}

然后当您想要启动计时器时, 只需拨打 < code> ScheduleWork (); 。 对于重复循环, 我个人认为这比上面的区块法更干净, 但有一次我绝对更喜欢区块法 。

“https:// developmenter.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/ reference.html' rel=“nofollow”>Grand Central Reference docs 以获得更多信息。





相关问题
List Contents of Directory in a UITableView

I am trying to list the contents of Ringtones directory in a TableView, however, I am only getting the last file in the directory in ALL cells, instead of file per cell. This is my code: - (...

iPhone NSUserDefaults persistance difficulty

In my app i have a bunch of data i store in the NSUserdefaults. This information consists of an NSObject (Object1) with NSStrings and NSNumbers and also 2 instances of yet another object (Object2). ...

Writing a masked image to disk as a PNG file

Basically I m downloading images off of a webserver and then caching them to the disk, but before I do so I want to mask them. I m using the masking code everyone seems to point at which can be found ...

Resize UIImage with aspect ratio?

I m using this code to resize an image on the iPhone: CGRect screenRect = CGRectMake(0, 0, 320.0, 480.0); UIGraphicsBeginImageContext(screenRect.size); [value drawInRect:screenRect blendMode:...

Allowing interaction with a UIView under another UIView

Is there a simple way of allowing interaction with a button in a UIView that lies under another UIView - where there are no actual objects from the top UIView on top of the button? For instance, ...

热门标签