title: Accurate timing in iOS
body: <p>I am looking at the 'Metronome' sample code from the iOS SDK (<a href="http://developer.apple.com/library/ios/#samplecode/Metronome/Introduction/Intro.html">http://developer.apple.com/library/ios/#samplecode/Metronome/Introduction/Intro.html</a>). I am running the metronome at 60 BPM, which means a tick every second. When I look at an external watch (the PC's watch), I see the metronome is running too slow - it misses about one beat each minute, which is app. 15msec of consistent error. The relevant code piece is:</p>
  
  <pre><code>- (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 &amp;&amp; ([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];    
  }
  </code></pre>
  
  <p>Where </p>
  
  <blockquote>
    <p>self.duration</p>
  </blockquote>
  
  <p>is 1.0 second in the case of 60 BPM. I wonder where this error comes from, and how can I make a more accurate timer/interval counter.</p>
  
  <p>EDIT: The problem exists as well when I change the sleep time to smaller values, e.g .001.</p>
  
  <p>EDIT2 (update): The problem exists as well when I use the <code>CFAbsoluteTimeGetCurrent()</code> method for timing. When I use the same method to measure timing between a button tap events, the timing seems accurate - I tap once a second (while watching a watch), and the measured rate is 60 BPM (on average). So I guess it must be some issue with the <code>NSThread</code> (?). Another thing is that on the device (iPod) the problem seems more severe then on the simulator.</p>