title: Simple Metronome
body: <p>I'm trying to write a simple metronome, by playing a system sound every 0.25 seconds. I use GCD to play the clicks on a separate thread but the playing is uneven with the clicks coming sometimes as two quick beats followed by a slower beat. I Logged the time when the if statement in the loop is executed and its right on 0.25 seconds. I'm hoping I don't have to use Audio Queue Services. Any suggestions?</p>
  
  <pre><code>- (IBAction)start:(id)sender 
  {
      dispatch_queue_t clickQueue; // the queue to run the metronome clicker
      dispatch_queue_t mainQueue; // I access the main queue to demonstrate how to change UIKit items
      //clickQueue = dispatch_queue_create("clickQueue", NULL);
      clickQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
      mainQueue = dispatch_get_main_queue();
      dispatch_async(clickQueue, ^{
          double timeWas = [NSDate timeIntervalSinceReferenceDate];
          //delay by a 1/10 of a second so the first few clicks don't bunch up.
          double timeIs = [NSDate timeIntervalSinceReferenceDate]  - 0.1; 
          // playing starts out as NO because it gets switched at the end of the loop
          // and the PlaySystemSound block isn't off the queue yet. There is probably a
          // better way to do this.
          while (playing) {
              timeIs = [NSDate timeIntervalSinceReferenceDate] ;
              if ((timeIs - timeWas) &gt; (60.0/240)) {
                  AudioServicesPlaySystemSound(sound);
                  timeWas = timeIs;
                  // I want to flast the 200 label between orange and black but I have to access
                  // user interface objects from the queue that they are running in, usually the
                  // main queue.
                  dispatch_async(mainQueue, ^{
                      if (flash)
                          [bpm setTextColor:[UIColor orangeColor]];
                      else
                          [bpm setTextColor:[UIColor blackColor]];
                      flash = !flash;
                  });
              }
          }
      });
      playing = !playing;
      if (playing) 
          [startButton setTitle:@"Stop" forState:UIControlStateNormal];
      else
          [startButton setTitle:@"Start" forState:UIControlStateNormal];
  }
  </code></pre>