1

I find the documentation on NSThread not very informative for newcomers in NSThread and i don't see any "this is THE boilerplate code" provided that contains all the code for NSThread with NSRunLoop. A lot of code pieces are scattered through the programming guide.

How does a good boilerplate example for starting a new NSThread look like?

Tomen
  • 4,854
  • 5
  • 28
  • 39
  • 2
    For threading I mainly use 'grand central dispatch' http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html – Justin Jan 31 '12 at 15:26
  • I second that, GCD is very simple and very powerful when it comes to threading! – George Green Jan 31 '12 at 15:41
  • i do too. this issue mainly is coming up, since i use the three20 network layer as base for my DAL. It uses an NSTimer to add a delay at some point and if you spawned a background task in GCD, it does not have a runloop in the spawned thread. NSTimer schedules itself in the (in this case nonexistent) runloop. so the thread will END the thread without notification and you will never get an answer from the TTURLRequest. That is why i want to spawn a background thread for networking – Tomen Feb 01 '12 at 09:28

2 Answers2

1

Each NSThread can inherently provide an NSRunLoop, so there's nothing to write there. All you really need be concerned with is pumping the NSRunLoop periodically (assuming you haven't attached any of the objects, such as NSTimer, that implicitly do this for you).

So e.g.

// create a thread and point it to an agent that
// knows how to pump the run loop
myThread = [[NSThread alloc] initWithTarget:self
                selector:@selector(startRunLoop)
                object:nil];

// start the thread
[serialDispatchThread start];

/* ... elsewhere ... */
- (void)startRunLoop
{
    // consider setting a thread name here, as it'll help with debugging

    // I'm lazily using a volatile bool for my quit flag; do whatever you
    // think is appropriate
    while(!quitThread)
    {
        // run the runloop for another 2 seconds, 
        // wrapping it in an autorelease pool
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

        [[NSRunLoop currentRunLoop] runUntilDate:
                [NSDate dateWithTimeIntervalSinceNow:2.0]];

        [pool drain];
    }
}

/* puts you in a position to be able, whenever you want to issue things like: */
[self
        performSelector:@selector(myAsynchronousAction)
        onThread:myThread
        withObject:nil
        waitUntilDone:NO];

So what you've done there is set yourself up with something a lot like a GCD serial dispatch queue.

Tommy
  • 99,986
  • 12
  • 185
  • 204
  • are you sure that an NSThread has a NSRunLoop by default? As i mentioned in a comment to my OP, if i spawn a task in GCD and it schedules an NSTimer, the thread will end and the timer will never fire. Since NSTimer schedules itself in the runloop, you need to explicitly call to the runloop. So i think a "GCD thread" does not make use of runloops. Stack traces that i have seen seem to support this argument. – Tomen Feb 01 '12 at 09:32
  • 1
    No, you're quite right - I missed the vital words "as needed" when reading Apple's docs. The correct explanation is that NSThreads inherently provide an NSRunLoop but it may be lazily allocated - see http://developer.apple.com/library/mac/ipad/#documentation/Cocoa/Reference/Foundation/Classes/NSRunLoop_Class/Reference/Reference.html – Tommy Feb 01 '12 at 09:52
  • i moved the init of the autoreleasepool out of the while-loop, to avoid a memory leak :) – Tomen Feb 01 '12 at 15:02
  • @Tomen I'm not sure your change is correct; autorelease pools are a special case because `drain` is synonymous with `release` in a reference counted environment but is also permitted under garbage collection, acting as a hint to the garbage collector. So I've changed it back, but if I'm missing something then please say so. – Tommy Feb 01 '12 at 16:14
  • oh sorry, i misunderstood the method. your arguments are correct. – Tomen Feb 01 '12 at 16:47
1

In case the original poster has a mistaken belief that s/he needs to always run NSRunLoop in an NSThread, let me mention the following:

If you just want another method to run in a different thread, you just do:

-(void)someMethod:(NSObject*)someObjectToBePassedIn
{
   the thing you'd like to do in a background thread
}

and then do

NSThread*thread=[NSThread detachNewThreadSelector:@selector(someMethod:) 
                                         toTarget:self withObject:someObject];

There's no third step!

Yuji
  • 34,103
  • 3
  • 70
  • 88
  • 3
    Or if the thread were just to run with a single method, I guess NSObject's `performSelectorInBackground:...` would also be an option? – Tommy Jan 31 '12 at 18:08