iOS 中的精确计时

2024-03-09

我正在查看 iOS SDK 中的“Metronome”示例代码(http://developer.apple.com/library/ios/#samplecode/Metronome/Introduction/Intro.html http://developer.apple.com/library/ios/#samplecode/Metronome/Introduction/Intro.html)。我以 60 BPM 的速度运行节拍器,这意味着每秒一格。当我查看外部手表(PC 的手表)时,我发现节拍器运行得太慢 - 每分钟大约错过一个节拍,这是应用程序。 15 毫秒的一致错误。相关代码片段是:

- (void)startDriverTimer:(id)info {    
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];       

    // Give the sound thread high priority to keep the timing steady.    
    [NSThread setThreadPriority:1.0];    
    BOOL continuePlaying = YES;   

    while (continuePlaying) {  // Loop until cancelled.   
        // An autorelease pool to prevent the build-up of temporary objects.    
        NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];     
        [self playSound];

        [self performSelectorOnMainThread:@selector(animateArmToOppositeExtreme) withObject:nil waitUntilDone:NO];    
        NSDate *curtainTime = [[NSDate alloc] initWithTimeIntervalSinceNow:self.duration];    
        NSDate *currentTime = [[NSDate alloc] init];  
        // Wake up periodically to see if we've been cancelled. 
        while (continuePlaying && ([currentTime compare:curtainTime] != NSOrderedDescending)) {     
            if ([soundPlayerThread isCancelled] == YES) {    
                continuePlaying = NO;    
            }    
            [NSThread sleepForTimeInterval:0.01];    
            [currentTime release];    
            currentTime = [[NSDate alloc] init];    
        }

        [curtainTime release];   
        [currentTime release];     
        [loopPool drain];    
    }    
    [pool drain];    
}

Where

自我持续时间

在 60 BPM 的情况下为 1.0 秒。我想知道这个错误从何而来,以及如何制作更准确的计时器/间隔计数器。

编辑:当我将睡眠时间更改为较小的值(例如 0.001)时,问题也存在。

EDIT2(更新):当我使用时也存在问题CFAbsoluteTimeGetCurrent()计时方法。当我使用相同的方法来测量按钮点击事件之间的计时时,计时似乎很准确 - 我每秒点击一次(在观看手表时),测量的速率为 60 BPM(平均)。所以我想这一定是有问题NSThread(?)。另一件事是,在设备(iPod)上,问题似乎比模拟器上更严重。


好的,经过更多测试后我有了一些答案,所以我与感兴趣的人分享。

我在里面放置了一个变量来测量刻度之间的时间间隔play方法(实际发送的方法play消息给AVAudioPlayer对象),正如我的简单与外部手表比较实验所示,60 BPM 太慢 - 我得到了这些时间间隔(以秒为单位):

1.004915
1.009982
1.010014
1.010013
1.010028
1.010105
1.010095
1.010105

我的结论是,在计算每 1 秒的间隔后,会消耗一些开销时间,并且在几十秒后,额外的时间(大约 10 毫秒)会累积到显着的量 -- 这对于节拍器来说非常糟糕。所以不是测量间隔between电话,我决定测量total与第一次调用的间隔,这样错误就不会累积。换句话说,我已经替换了这个条件:

while (continuePlaying && ((currentTime0 + [duration doubleValue]) >= currentTime1)

有了这个条件:

while (continuePlaying && ((_currentTime0 + _cnt * [duration doubleValue]) >= currentTime1 ))

现在在哪里_currentTime0 and _cnt是类成员(抱歉,如果这是一个 C++ 术语,我对 Obj-C 还很陌生),前者保存第一次调用该方法的时间戳,后者是一个int计算刻度数(==函数调用)。这导致了以下测量的时间间隔:

1.003942
0.999754
0.999959
1.000213
0.999974
0.999451
1.000581
0.999470
1.000370
0.999723
1.000244
1.000222
0.999869

很明显,即使不计算平均值,这些值也会在 1.0 秒左右波动(平均值接近 1.0,精度至少为一毫秒)。

我很高兴听到更多有关导致额外时间流逝的原因的见解 - 对于现代 CPU 来说 10 毫秒听起来像是永恒 - 尽管我不熟悉 iPod CPU 的规格(它是 iPod 4G,维基百科说 CUP 是 PowerVR) SGX GPU 535 @ 200 MHz)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS 中的精确计时 的相关文章

随机推荐