rizzes rizzes - 1 year ago 63
iOS Question

NSTimer Not Firing in Subthread

I am trying to get a

to fire in a subthread. My code essentially looks like this:

-(void) handleTimer:(NSTimer *)theTimer {
NSLog(@"timer fired");

-(void) startMyThread {
// If I put timer in here, right before I start my new thread, it fires.
// [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleTimer:) userInfo:nil repeats:NO];
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

// This method is called from inside the new thread
-(void) playNote:(Note *)theNote withTemplate:(NSString *)theTemplate X:(int)x andY:(int)y {
NSLog(@"before timer");
// The timer doesn't fire in here. (But the print statements do.)
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(handleTimer:) userInfo:nil repeats:NO];
NSLog(@"after timer");

I would really like to (read:need to?) fire the timer in the subthread because it is going to be used to stop notes from playing (and all of the note playing needs to happen in a subthread).

I must be missing something with how a
runs in subthreads...

Premature thanks for the help!

Answer Source

A timer won't fire unless it is scheduled in a run loop. You'll also want to avoid spinning up threads willy-nilly.

Unless your run method fires up a run loop, your timer won't fire.

A better solution, btw, might be to use GCD's dispatch_after(). It is lighter weight than a thread, but it depends on what you need to do. In general, though, queues are a more efficient means of adding concurrency to an app.

Grabbing the code from the comment for proper formatting (good find):

double delayInSeconds = .2;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    NSLog(@"dispatch popped");

One additional note; you might consider using one of the global concurrent queues. They won't block when the Main Event Loop might block. Of course, if you are updating the UI, you have to go back to the MEL anyway.