Wednesday, November 4, 2009

iPhone NSTimer on separate loop

This is a quick post about the usage of NSTimer to create a multi-threaded experience within an iPhone application. It does NOT address "backgrounding" or other challenges with creating threads in the highly restricted iPhone OS runtime.

I encountered this problem when I was trying to recreate a stopwatch application similar to the "Stopwatch" tab in the "Clock" application. I had an NSTimer object firing every tenth of a second, updating the label displaying the duration by calling a method "updateLabels".

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:(0.1) target:self selector:@selector(updateLabels) userInfo:nil repeats:YES];


This quickly demonstrated my naivete regarding how the iPhone OS environment handles its run sequence. What happened was when the user touched the phone, my timer was delayed hence there was a noticeable lag (not firing until the user stopped touching the screen) in updating the labels. As this was not happening on the apple supplied app, I hit the search trail and found out about the "NSRunLoop" in this post. This object controls the run sequence of events in the app lifecycle and it places user events ahead of scheduled threads. The correct way of running the timer was hence:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSRunLoop *runLoop = [NSRunLoop currentRunLoop];

NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:(0.1) target:self selector:@selector(updateLabels) userInfo:nil repeats:YES];

[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

[pool release];

No comments: