Create a timer on 2nd thread using Grand Central Dispatch GCD

Posted in :

stlplace
Reading Time: 2 minutes

(Update 06-24-11) Last night I found “More iPhone 3 development” (by Dave mark and Jeff Lamarche) chapter 14 deveoted full chapter to multithread including timer.

(Original) As of iOS 4, Apple made blocks and Grand Central Dispatch (GCD) available. Previously it was available on Mac.

Some pre-requisite or recommend readings
WWDC 2010 video session 206: Introduction to Blocks and Grand Central Dispatch GCD (you need to be a registered Apple developer to download this).

Or if you read the nice intro “guide to blocks and grand central dispatch by Cocoa Samurai (Colin Wheeler).

The problem I attempt to solve
I have couple buttons waiting for the user to touch, and the buttons can not wait there forever, they wait for 2 seconds if a user does not touch any of them, and a new set of button will display at that time.

I thought about this problem for a while, thought about using NSNotifications which is essentially a callback mechanism (see “love to be notified” by Cocoanetics for more info). I need more, essentially I need a second thread which is a timer, to notify the main thread (which does display and handles touch) when 2 seconds is up.

I found fieryrobot’s Watchdog timer in GCD which meets my basic need for timer. But I need to return from timer to the main thread. Quote Fieryrobot:

…If you needed to return results to your main thread, you can just use dispatch_async to execute the code on the main queue (dispatch_get_main_queue() as we’ve seen in previous posts…

I am sure there is ways using blocks (callbacks) to do that, but I don’t know on top of my head. So I used Notification instead. Here is what I did in ViewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(twoSecondsNotification:)
name:@"TwoSecondsReached"
object:nil];

In the timer, I post notification when it’s time to go back to main queue (thread).
// Hey, let's actually do something when the timer fires!
dispatch_source_set_event_handler(_timer, ^{

NSLog(@"WATCHDOG: task took longer than %f seconds",
timeout);
// ensure we never fire again
dispatch_source_cancel(_timer);

// pass control back to main queue
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:@"TwoSecondsReached" object:nil userInfo:nil];
});

last but not least, the “TwoSecondsReached” function
- (void)twoSecondsNotification:(NSNotification *) notification
{
// clean up the timer here
if(timer != nil)
{
[timer invalidate];
[timer release];
}

// do things you want to do here.
}

One more thing
In my code, I initialize timer and release timer in different methods, and I found it’s easy to lose tack of timers and have multiple timers. One phenomena I saw is multiple timers fire at the same time, and make the app go crazy. I am thinking use a singleton pattern for the timer at this time.

%d bloggers like this: