How to make NSRunLoop work inside a separate thread?

Andrey Chernukha picture Andrey Chernukha · Mar 22, 2012 · Viewed 7.8k times · Source

Please look at this code:

@interface myObject:NSObject

-(void)function:(id)param;

@end

@implementation myObject

-(void)function:(id)param
{
    NSLog(@"BEFORE");
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:20]];
    NSLog(@"AFTER");
}

@end


int main(int argc, char *argv[])
{
    myObject *object = [[myObject alloc] init];

    [NSThread detachNewThreadSelector:@selector(function:) toTarget:object withObject:nil];

    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

The function method is called but there's no 20 seconds pause. What should i do to make NSRunLoop work in a detached thread?

Answer

Krumelur picture Krumelur · Mar 22, 2012

Since you are running the function: selector in a different thread, [NSRunLoop currentRunLoop] is not the same as in the main thread.

Please see NSRunLoop reference:

If no input sources or timers are attached to the run loop, this method exits immediately

I guess that your run loop is empty, and therefore the "BEFORE" and "AFTER" logs will appear instantaneously.

A simple solution to your problem would be

@implementation myObject

-(void)function:(id)param
{
  NSLog(@"BEFORE");
  [[NSRunLoop currentRunLoop] addTimer:[NSTimer timerWithTimeInterval:20 selector:... repeats:NO] forMode:NSDefaultRunLoopMode];
  [[NSRunLoop currentRunLoop] run];
  NSLog(@"AFTER");
}

@end

In reality, you would probably put the code that logs "AFTER" in a new method that is called by your timer. In general, you do not need threads to do animations (unless you are doing something computationally expensive). If you are doing computationally expensive stuff, you should also look into using Grand Central Dispatch (GCD), which simplifies off-loading calculations on background threads and will handle the plumbing for you.