Worker Thread iOS - iphone

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:
Create a background worker thread
Trigger the execution of a method every 10msec. (probably by using a NSTimer in that thread?)
Put as less load on the main application thread as possible
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?

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);

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.

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.

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;

Related

self performSelector:withObject: afterDelay: does not call method

I am developing an iPhone application where I'm trying to call particular method after certain delay. But the method is not getting called. I have no clue why its not getting called.
Here is my code
-(void)gettingCommentsList { // some stuff....
[self performSelector:#selector(callGetListInBackgroundMethod) withObject:nil afterDelay:1.0]; }
-(void)callGetListInBackgroundMethod {
isFromthread =YES;
NSLog(#"callGetListInBackground");
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Add code here to do background processing
//
//
[self gettingCommentsList];
dispatch_async( dispatch_get_main_queue(), ^{
// Add code here to update the UI/send notifications based on the
// results of the background processing
[self.commentsTbl reloadData];
});
});
}
Thanks
One potential problem is that timers do not prevent threads from exiting before the timer's fired. So if the run loop (of the thread which calls -performSelector:withObject:afterDelay:) has no other source (work), it may not continue running for one second or more and the thread will exit before your timer fires (and your custom work is executed).
That's certainly possible if you schedule the timer on a secondary thread.
I suspect the reason for this design is because timers may be configured as recurring (or not) -- a lot of people would end up with 'zombie' threads because those recurring timers would never be invalidated. That problem could easily chew up a ton of system resources.
Make sure you are not calling [NSObject cancelPreviousPerformRequestsWithTarget:self]
You seem to be calling each method from the other -
In gettingCommentList, you call
[self performSelector:#selector(callGetListInBackgroundMethod) withObject:nil afterDelay:1.0];
and in callGetListInBackgroundMethod in dispatch_async you call
[self gettingCommentList];
Edit:
Try making the call just once and see if it works. If it does, it might be that you're not done with the first call before the second one begins, hence the problem. Let me know what happens.
Edit 2:
I tried your code. The problem is the the subsequent calls to gettingCommentList are in the background thread rather than the main thread. So I did this:
dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Add code here to do background processing
//
dispatch_async( dispatch_get_main_queue(), ^{
[self gettingCommentsList];
});
});
and it works. But make sure you don't call the two functions continuously as this would make them run all the time, which I'm sure you don't really want :-)

How do I kill/suspend/close an asyncronous block in GCD?

I've implemented a block that is dispatched asynchronously using GCD as follows:
__block BOOL retValue;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
retValue = [self GCDHandler:actionName WithServiceType:serviceType :arguments];
});
return retValue;
How do I cancel such a block if it is running for longer than I would like? Is there a way to cancel GCD-dispatched blocks, or provide a timeout to them?
There is no built in way to cancel GCD blocks. They're rather set and forget. One way I've done this in the past is to provide 'tokens' for blocks.
- (NSString*)dispatchCancelable:(dispatch_block_t)block
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
if (!checkIfCanceled)
block();
}
return blah; //Create a UUID or something
}
- (void)cancelBlock:(NSString*)token
{
//Flag something to mark as canceled
}
That depends on what your GCDHandler is doing. There's some pretty good videos about GCD on the Apple dev site - you might want to move up a layer (into Cocoa) and use NSOperationQueue and NSOperations (either your own subclass or NSBlockOperation). They're all built on top of GCD and the abstraction layer might be more appropriate for what you are trying to do (which you don't state - is it a network request? etc.)

iPhone 4 is there an absolutely certain way to have a long term NSTimer fire

I keep having troubles with my NSTimers and background selectors. It is driving me nuts and takes a very long time to try out each tweak. To preserve my sanity, and the sanity of future generations of cocoa programmers, I'm asking this question:
Is there an absolutely 100% sure way to have a scheduled, long-term timer fire at a later point in time, regardless of whether it was called from a background thread, main thread, etc?
It seems that I keep having to solve the same problem over and over again for the majority of my classes that use NSTimers. they work during short-term testing, let's say I set the timer to fire through a background thread to fire in 10 seconds. It works, because there's still a run loop running. But once I change the fire time to what I really want, like 15-30 minutes, there's dead silence. The run loop is gone and I don't know how to handle such a case. Nothing happens, and I discover such bugs a few days later, once I've already forgotten which timer would be responsible for that.
Currently I'm doing some really, really ugly dance with selectors, for example here's a test method(It seems to work for 10 minute timers):
//this is a test method to simulate a background task requesting a timer
[self performSelectorInBackground:#selector(backgroundReminderLongTermTest:) withObject:nil];
//this is a method similar to the one that the background thread would be trying to invoke
-(void)backgroundReminderLongTermTest:(id)sender
{
[self performSelectorOnMainThread:#selector(backgroundReminderFromMainThread:) withObject:nil waitUntilDone:NO];
}
//this is a wrapper for the background method, I want the timer to be added to a thread with a run loop already established and running
-(void)backgroundReminderFromMainThread:(id)sender
{
[playTimers addObject:[NSTimer scheduledTimerWithTimeInterval:1800 target:self selector:#selector(start:) userInfo:nil repeats:NO]];
}
I like the convenience of not having to worry about creating a fire date object with the scheduled timers, but should I just forget about them and use timers with specific fire dates? It seems that the scheduledTimer works well for short term tasks, when the run loop is already present, but I simply cannot see this kind of bugs during the app's execution. At one point, it seems that the timers are firing normally, but at a later point they stop firing completely.
Thank you for any help or clarification. I'm looking for a method that schedules timers without having to worry about whether or not a run loop is present every time I need to schedule a timer. I want to be sure that as long as the app is running, my timers, scheduled through this method would fire at predictable points in the future .
One of the myriad issues with NSTimers is their run-loop dependency. Every thread has a single run loop. If you schedule a timer on a background thread, it will be scheduled on that thread's run loop. If that thread is short lived, which background threads often are, that timer will quietly die with it.
The solution is to guarantee the timer is run on a thread that will be alive when the timer fires. The best way to do these dedicated background timers in my experience is to not use NSTimer at all, and go for GCD timers instead. Better men than I have coded up GCD powered timers. I personally prefer Mike Ash's article and implementation, which comes with an explanation.
Use local notification instead.
For as long as you depend on using scheduledTimerWithTimeInterval:... you cannot achieve what you want:
The timer will always be tied to the run-loop of the calling thread.
If there is no run-loop associated with that thread by the time of that message's invocation, there surely is one when the method returns as -[NSRunLoop currentRunLoop] creates a run-loop if necessary.
What you can do, if you don't like the other APIs for creation of a timer, is providing a category on NSTimer, which takes care of all the scheduling and so forth and that you can reuse in other projects.
Here is an example of what such a category might look like:
#pragma mark - setting up a timer:
+ (NSTimer *)yourPrefix_mainLoopScheduledTimerWithTimeInterval:(NSTimeInterval)interval target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
{
NSTimer *timer = [self yourPrefix_timerWithTimeInterval:interval target:target selector:selector userInfo:userInfo repeats:shouldRepeat];
void (^scheduler)() = ^{
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
};
if ([NSThread isMainThread]) {
scheduler();
} else {
// you should really be able to rely on the fact, that the timer is ready to roll, when this method returns
dispatch_sync(dispatch_get_main_queue(), scheduler);
}
return timer;
}
// this is just a convenience for the times where you actually want an _unscheduled_ timer
+ (NSTimer *)yourPrefix_timerWithTimeInterval:(NSTimeInterval)interval target:(id)target selector:(SEL)selector userInfo:(id)userInfo repeats:(BOOL)shouldRepeat
{
NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:interval];
NSTimer *timer = [[self alloc] initWithFireDate:fireDate interval:interval target:target selector:selector userInfo:userInfo repeats:shouldRepeat];
return [timer autorelease];
}
#pragma mark - tearing it down:
- (void)yourPrefix_invalidateMainLoopTimer
{
[self yourPrefix_invalidateMainLoopTimerAsynchronous:NO];
}
- (void)yourPrefix_invalidateMainLoopTimerAsynchronous:(BOOL)returnsImmediately
{
void (^invalidator)() = ^{
[self invalidate];
};
dispatch_queue_t mainQueue = dispatch_get_main_queue();
if (returnsImmediately) {
dispatch_async(mainQueue, invalidator);
return;
}
if (![NSThread isMainThread]) {
dispatch_sync(mainQueue, invalidator);
return;
}
invalidator();
}
Note the thread checks before using dispatch_sync because...
dispatch_sync
Discussion
[…] Calling this function and targeting the current queue results in deadlock.
(from The GCD Reference — emphasis mine)

How does multithread work in objective-c?

In the scenario in which i have a thread launched, can i still acces methods on the parent thread? Is there a specific way to call this methods? If so, what is it?
Note: in my scenario both thread are for data manipulation, they are not interface-related threads ( i know this was to be considered in .NET, don't know it they are in Objective-c).
In this case, it is best to use Grand Central Dispatch (GCD) instead of working with NSThead or NSOperation directly.
Overview of Concurrency: http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008091
Intro to Grand Central Dispatch: http://cocoasamurai.blogspot.com/2009/09/guide-to-blocks-grand-central-dispatch.html
With your example, you can use nested calls into Grand Central Dispatch to achieve this functionality:
dispatch_queue_t backgroundQueue = dispatch_queue_create("com.example.exampleQueue", 0);
dispatch_async(backgroundQueue, ^{
// operate on data in the background here
NSData *stuff = [self doSomethingComplex];
dispatch_async(dispatch_get_main_queue(), ^{
// Perform Task back in the main thread
[viewController updateStuff:stuff];
});
});
This method is the preferred method for performing these kind of tasks. In addition, by utilizing blocks, it is also very easy to understand the code at a glance without having to example multiple methods within your class.
Threads by definition share the state of parent thread. In ObjectiveC, if you spawn a worker thread & want to call some method on main thread, this can be done like so-
[self performSelectorOnMainThread:#selector(someMethod:) withObject:nil waitUntilDone:NO];
If they are not interface stuff, or can result in some interface stuff you can call then you can just call then, and do any of the usual thread safety stuff you have to do in any language, like #syschronise(obj) or NSLock. But if it is stuff that will result in interface stuff then you will have to do as 'Srikar' wrote [self performSelectorOnMainThread:#selector(setDataCount:) withObject:count waitUntilDone:NO]; which will effectively place the message onto the NSRunLoop cue.

objective-c/iphone: how to set that all methods of some object will run on a specific thread?

here is what i want:
create an object that 'lives' in its own thread, all the methods should be executed in that thread.
i.e:
// i'm in the main thread
MyClass *myObject = [ [MyClass alloc] init ]; // it creates its own thread
[myObject method1]; // should execute the method1 in myObject's thread
[myObject method2]; // should execute the method2 in myObject's thread
[myobject release]; // should deallocate everything that is used for myObject and remove myObject's thread
i have been reading about threads and runloops. I created a new thread on the init method, its entry point is the runloop method. The runloopMethod just set the most basic stuff needed for running a NSRunLoop and runs it.
aThread = [[NSThread alloc] initWithTarget:self selector:#selector(runloopMethod) object:nil];
[aThread start];
it worked fine, but when i call a method ( i.e: [myObject method1];) from the main thread it runs it on the main thread, how do i know it?, well, because method1 performs several operations that blocks the UI. What i have done is to redirect the call in this way:
// on MyClass.m
-(void) method1 {
if ([NSThread currentThread] != aThread) {
[self performSelector:#selector(method1) onThread:aThread withObject:nil waitUntilDone:YES];
}else {
// do my stuff
}
it's working, but this way limits me, also i have some questions for you:
i have realized that if i'm in X-thread and call a method of some object, it will be executed in X-thread. I think that the method call will be added (not sure if it's the word) to the X-thread's runloop. right?
Is there a way to set that: any call to my object's methods will be executed on the object's thread? (without doing all this stuff).
also, is it the correct way for what am i doing?
method1, method2, and so on are the sync version of my functions..so they will block the UI. that' why i assume having another thread is the way.
thanks for reading!.
btw. i'm not using GCD since i need to support iOS 3
The Objective C method dispatch runtime code has no mechanism (AFAIK) to determine implicitly whether to do a generic method call on a different thread than the current one, so you will have to implement your own explicit background call mechanism, as you did, using performSelector.
If you set waitUntilDone to YES on your call to your background thread from the main thread, you will still block the UI.
If you want your method1 to run in the background and not block the UI, set waitUntilDone to NO, and have to background thread inform the main thread about completion (or anything else) using performSelectorOnMainThread.
You might alternatively be able to use operation queues to send messages to your background thread's run loop.
I'm guessing you are trying to use threads to run background tasks in order to keep the UI responsive. That's good, but this would be a very difficult approach. Try this instead:
1) From the main thread, fire off a new thread:
[NSThread detachNewThreadSelector:#selector(methodThatTheThreadWillRun)
toTarget:nil
withObject:nil];
2) Write methodThatTheThreadShouldRun and do whatever you need to do in it. It will be executed in the thread you just created. When it finishes, have it call a threadIsFinished on the main thread:
- (void)methodThatTheThreadWillRun {
MyClass *myObject = [ [MyClass alloc] init ];
[myObject method1];
[myObject method2];
[myobject release];
[self performSelectorOnMainThread:#selector(threadIsFinished)];
}
3) Finally, write threadIsFinished:
- (void)threadIsFinished {
// do whatever you need to do here: stop a spinner, etc.
// this will be invoked by the background thread but will
// execute on the main thread
}