Keep NSThread alive and run NSRunLoop on it

Erik Rothoff picture Erik Rothoff · Jun 8, 2011 · Viewed 15.3k times · Source

So I'm starting a new NSThread that I want to be able to use later by calling performSelector:onThread:.... From how I understand it calling that methods add that call to the runloop on that thread, so on its next iteration it will pop all these calls and subsequently call them until there is nothing left to call. So I need this kind of functionality, an idle thread ready for work that I just can call upon it. My current code looks like this:

   - (void)doInitialize
   {
       mThread =  [[NSThread alloc] initWithTarget:self selector:@selector(runThread) object:nil];
       [mthread start];
   }

   - (void)runThread
   {
       NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];

       // From what I understand from the Google machine is that this call should start the
       // runloop on this thread, but it DOESN'T. The thread dies and is un-callable
       [[NSRunLoop currentRunLoop] run];

       [pool drain];
   }

   - (void)scheduleSomethingOnThread
   {
       [self performSelector:@selector(hardWork) onThread:mThread withObject:nil waitUntilDone:NO];
   }

But the thread is not kept alive, and the performSelector:onThread does not do anything. How do I go about this the right way?

Answer

John Calsbeek picture John Calsbeek · Jun 8, 2011

A run loop requires at least one "input source" to run. The main run loop does, but you have to add a source manually to get a secondary run loop's -run method to do anything. There's some documentation on this here.

One naïve way to get this to work would be just to put [[NSRunLoop currentRunLoop] run] in an infinite loop; when there's something to do, it'll do it, and return immediately otherwise. The problem is that the thread will take a decent amount of processor time simply waiting for something to occur.

Another solution is to install an NSTimer on this run loop to keep it alive.

But, if possible, you should use a mechanism designed for this sort of thing. If possible, you may want to use NSOperationQueue for background operations.