It would help to know exactly what you're trying to accomplish here, because the meta-question is whether NSThread
is the right tool for the task. GCD is often preferred.
Nonetheless, one of the things to consider is whether the NSRunLoop
has an input source or not. Let's take a slightly simplified case where we detach a new NSThread
as follows:
- (void)viewDidLoad
{
[super viewDidLoad];
_threadCheck = NO; // this is an ivar
[NSThread detachNewThreadSelector:@selector(kickOffThread) toTarget:self withObject:nil];
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
for( uint8_t i = 0; i < 10; i++ )
[self performSelector:@selector(logSomething) onThread:self.thread withObject:nil waitUntilDone:NO];
[self performSelector:@selector(signalThreadCheck) onThread:self.thread withObject:nil waitUntilDone:NO];
});
}
- (void)kickOffThread
{
_thread = [NSThread currentThread]; // this is an ivar
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
while( !_threadCheck && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] );
[self doSomeCleanUp];
printf("thread exit...\n");
}
- (void)doSomeCleanUp {
printf("cleaning up...\n");
}
- (void)logSomething {
printf("in background thread...\n");
}
-(void)signalThreadCheck
{
printf("signalThreadCheck\n");
_threadCheck = YES;
}
On the console, I get:
cleaning up...
thread exit...
Why was logSomething
never called? Because the run loop for the background thread that we spawned has no input source, so it exits immediately. If we add an input source with [NSPort port]
for example, we can keep the spawned thread's run loop turning, e.g.:
- (void)kickOffThread
{
_thread = [NSThread currentThread];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSPort port] forMode:NSRunLoopCommonModes];
while( !_threadCheck && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] );
[self doSomeCleanUp];
printf("thread exit...\n");
}
Now we print the following to the console:
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
in background thread...
signalThreadCheck
cleaning up...
thread exit...
More about run loops and from the documentation:
If no input sources or timers are attached to the run loop, this
method [run] exits immediately; otherwise, it runs the receiver in the
NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:. In
other words, this method effectively begins an infinite loop that
processes data from the run loop’s input sources and timers.