m Jae
m Jae

Reputation: 725

Worker Thread iOS

I want to create a background thread on the iPhone that executes some code every 10msec. But before I get lost in the concurrency programming guide and the threading programming guide of apple again, I wanted to ask whether someone here can help me out. What I want to do:

In my understanding subclassing NSThread and writing my own main method in that subclass should do the trick. That way I don't use an NSTimer for the update intervals but something like:

[NSThread sleepForTimeInterval: 0.01];

Also queuing mechanisms between main thread and worker thread don't make any sense, as the worker thread should perform the same operation over and over - until stopped.

The question is: How can I configure the thread to use a timer? I can't see how I can attach a NSTimer to that worker threads Run Loop?

Upvotes: 3

Views: 7980

Answers (4)

weezor
weezor

Reputation: 2631

It is pretty simple and clean if you do it with NSThread. With no need to subclass it.

- (void)backgroundStuff {
    while (!self.cancelThread) {
        // do your work
        [NSThread sleepForTimeInterval:0.01];
    }
}

Just an ordinary function. cancelThread is a member variable you declare. Start it with

[NSThread detachNewThreadSelector:@selector(backgroundStuff) toTarget:self withObject:nil];

and you can cancle the thread anytime with self.cancelThread = true;

Upvotes: 0

justin
justin

Reputation: 104698

NSRunLoop is the missing link.

You will have to setup the thread's run loop to repeat, or you can control this from your thread's entry. the thread hosts the timer (the timer will die with the run loop if it's still alive).

NSRunLoop is a pretty small class - check it and the related samples out.

Upvotes: 2

Mihai Fratu
Mihai Fratu

Reputation: 7663

You could easily use GCD (grand central dispatch) for that. First create a selector that will be called in the background. From here call whatever method you want.

- (void)backgroundSelector
{
    // do whatever you want to do
    [self performSelector:@selector(backgroundSelector) withObject:nil afterDelay:0.01];
}

After that just fire this method for the first time like this

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
    [self backgroundSelector];
});

Let me know if that works for you.

Upvotes: 1

Andrew Madsen
Andrew Madsen

Reputation: 21373

It's possible to do this using the method you outline, but have you looked at using Grand Central Dispatch? It can make some of this a lot easier:

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(backgroundQueue, ^{
    while ([self shouldKeepProcessingInBackground]) {
        [self doBackgroundWork];
        usleep(1e4);
    }
})

You can also use a timer dispatch source to do work periodically:

dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_source_t timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, backgroundQueue);
dispatch_source_set_timer(timerSource, dispatch_time(DISPATCH_TIME_NOW, 0), 0.01*NSEC_PER_SEC, 0*NSEC_PER_SEC);
dispatch_source_set_event_handler(timerSource, ^{
    [self doBackgroundWork];
});
dispatch_resume(timerSource);

Upvotes: 11

Related Questions