self performSelector:withObject: afterDelay: does not call method - iphone

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

Related

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

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)

Threading, priorities, and abandonment

I have recently become thread curious on iOS. Please point me in the direction you would take, to achieve (if possible) the following on modern iOS devices... thank you!
The user is typing in text, say a word every few seconds.
From time to time I want to launch DifficultProcess to do some semantic processing. In short, I guess I need to be able to do four things:
launch DifficultProcess from main
if DifficultProcess completes, get a message back from it to the same main
abandon, get rid of, DifficultProcess if I want to, from main
and finally the priority question: DifficultProcess must have much lower priority than main or user input, I want DifficultProcess to have really really looow priority; is that even possible?
What, essentially, are the calls one uses for A, B, C in modern (2011) (late January) iOS? I don't care about Dad's methods! And is "D" even possible in any way?
I guess those are the four ideas!
So in particular I want to send a message to, in other words call a routine in, the running background process (in that way, one could kill off the running background process if desired, or perhaps change it's mode of operation etc).
(For anyone born before 1997, you will recognise that as a typical "speculative processing" paradigm.)
Thanks for pointers for anyone who can be bothered on this!
I would recommend using NSOperation and NSOperationQueue to manage background activity that you need to be able to cancel arbitrarily.
NSOperation's -cancel and NSOperationQueue's -cancelAllOperations are the methods to look at.
To get messages back from the background to the main thread, the dispatch_async-to-main-thread-queue technique is fine. You can combine this with a delegate protocol for your NSOperation to codify the messages you want to send back.
E.g.
#protocol MyOperationDelegate
- (void) operationStarted:(MyOperation *)operation;
- (void) makingProgressOnItem:(id)anItem otherInterestingItem:(NSDictionary *)otherItem remainingCount:(NSUInteger)count;
- (void) operationWillFinish:(MyOperation *)operation;
#end
#interface MyOperation
id <MyOperationDelegate> delegate;
#end
#implementation MyOperation
...
- (void) cancel
{
[super cancel];
// Tell the delegate we're about to finish (due to cancellation).
dispatch_sync (dispatch_get_main_queue(), ^{
[self.delegate operationWillFinish:self];
});
}
- (void) main
{
// Check for cancellation
if (self.isCancelled) return;
// Starting
dispatch_sync (dispatch_get_main_queue(), ^{
[self.delegate operationStarted:self];
});
if (self.isCancelled) return; // Another cancel check
// Send async progress messages periodically while doing some work
while (workNotDone)
{
// Do some work ...
dispatch_async (dispatch_get_main_queue(), ^{
[self.delegate makingProgressOnItem:foo otherInterestingItem:bar remainingCount:baz];
});
if (self.isCancelled) return;
}
// About to finish
if (!self.isCancelled) {
dispatch_sync (dispatch_get_main_queue(), ^{
[self.delegate operationWillFinish:self];
});
}
}
#end
KVO is no good for interthread communication; the observation is received on the thread that originates the key value change. So, if your background thread changes a value, your background thread is going to receive the KVO about it. Probably not what you want.
Grandpa's -performSelectorOnMainThread:withObject:waitUntilDone: continues to be a fine way to get messages back to the main thread. The limitation is that your messages can only access one object-based argument. The dispatch_async to the main thread doesn't have this limitation.
If you want to fire off an asynchronous (or synchronous) NSNotification's from a background thread to the main thread, you need to use -performSelectorOnMainThread.
NSNotification *note = [NSNotification notificationWithName:FinishedABunchOfWorkNotification object:self userInfo:nil];
[[NSNotificationCenter defaultCenter] performSelectorOnMainThread:#selector(postNotification:) withObject:note waitUntilDone:YES];
I would suggest using dispatch_async to the global low priority queue (dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)).
Cancellation is trickier though. There's no good general mechanism for canceling background work that I'm aware of aside from "chunking" it and checking a flag each chunk
To get messages back just dispatch_async back to the main queue. If you squint just right you can think of dispatch_async as "send message" in an actor model.
(edit) if you need serialization of stuff in the background, make a private queue and set its target to the global low priority one, iirc.
At the risk of quoting Dad's method (it has been around since iPhone version 2) I use
- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg
It's easy and foolproof as long as you remember that you must create a new autorelease pool in the method you pass as selector, and drain it at the end of the method. Apart from that do whatever you like - EXCEPT touch UIKit. It isn't thread-safe so any UI changes must be done through
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
or KVO triggers. Key Value Observing would be a good way for your background thread to communicate to your main thread that the work is done.
- (void)myBackgroundThreadMethod {
NSAutoreleasePool *threadPool = [[NSAutoreleasePool alloc] init];
// my time-consuming processing here
[threadPool drain];
}
For more precise control of threads you need to look at NSThread. Threading Programming Guide lays it all out in detail - if you create a thread through NSThread then you have control over when the thread is started. The document does recommend leaving the thread alone and just letting it terminate - but shows how you can terminate it. One way is - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait
NSThread docs also say "leave priority alone". You can set thread priority with
+ (BOOL)setThreadPriority:(double)priority
but I've never known it to be necessary, the scheduler is smart enough to maintain UI responsiveness.

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
}

Call a delegate's method within a background

this is my first question here, so excuse me if I made any mistakes!
In my iPhone project I have a method running in a thread which takes a long time to execute (that's why it runs in a thread).
[NSThread detachNewThreadSelector:#selector(methodToBeCalledInAThread) toTarget:self withObject:nil];
// ...
-(void)methodToBeCalledInAThread {
MyClass *myClass = [[MyClass alloc] init];
[myClass setDelegate:self];
[myClass veryIntensiveComputing];
[myClass release];
}
My goal is to notifiy the ViewController calling this method of any progress going on in this method. This is why I set the ViewController as a delegate of the class.
Now in the expensive method I do the following:
if(self.delegate != nil) {
[self.delegate madeSomeProgress];
}
But unfortunately this does not work, because (I think) I'm in a background thread.
How do I achieve to notify the delegate of any changes with the method being executed asynchronously?
Try [self.delegate performSelectorOnMainThread: #selector(madeSomeProgress) withObject: nil waitUntilDone: YES];....
See the documentation for details.
This will synchronously perform the operation on the main thread. As long as nothing in the main thread tries to execute stuff in that secondary thread, this is mostly safe to do.
However if you don't want to block the computation until the main thread services the request, you can pass NO to not wait. If you do so, then you also have to worry about thread synchronization. The main thread may not immediately service the request and, when it does, your background thread may be in the process of mutating state.
Threads are hard.