10

I have an application that is supposed to log certain things every 1 second and I'm currently using NSTimer, but if my application transitions screens (or almost anything else, really) it slows down the timer a little bit making for inaccurate readings.

What is a reliable alternative to use? My current code is as follows:

timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(update) userInfo:nil repeats:YES];
Baub
  • 5,004
  • 14
  • 56
  • 99

2 Answers2

14

NSTimer is not guaranteed to fire exactly on time, ever. But you can use an NSTimer in a much more reliable way than you are now. When you use scheduledTimerWithTimeInterval you create an NSTimer which is scheduled in the run loop for NSDefaultRunLoopMode. This mode is paused when the UI is being used, so your timers won't fire when there is user interaction. To avoid this pause use the mode NSRunLoopCommonModes. To do this you will have to schedule the timer yourself like so:

timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(update) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
NJones
  • 27,139
  • 8
  • 70
  • 88
  • Alright, I'll change this out now. Do I invalidate the timer the same way `[timer invalidate]`? – Baub Nov 17 '11 at 20:29
  • A timer created in this way interacts identically. Except that you have to add it manually. When you call invalidate it should be automatically removed from the runloop just like before. – NJones Nov 17 '11 at 20:39
4

You could:

  • Put the NSTimer in a different thread (it may not be affected by the UI that way)
  • Decrease the interval (say 0.1 second) and, in your logging function, check if it is the "right" time to log what you want.
Sergio Moura
  • 4,888
  • 1
  • 21
  • 38
  • doesn't NSTimer creates its own new thread...? just asking...i read somewhere that it does. – Ankit Srivastava Nov 17 '11 at 19:11
  • I tried putting the timer in a different thread by calling `performSelectorInBackground` but it would not call the selector when it fired (I guess because it is in a different thread). – Baub Nov 17 '11 at 19:18
  • 2
    @Steve: `NSTimer` does not create its own thread. It runs on the thread where it was created. – jscs Nov 17 '11 at 19:29
  • 1
    Decreasing the interval is a good solution. `NSTimer` [isn't a real-time mechanism](http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/Timers/Articles/timerConcepts.html#//apple_ref/doc/uid/20000806-SW2). – jscs Nov 17 '11 at 19:31
  • Also give a try at Grand Central Dispatch (GCD). It can also be used to create timers. Maybe they will be more reliable. – Macmade Nov 17 '11 at 20:03