cancelPreviousPerformRequest from background thread issue - iphone

I have the following code, which is executed when a button is pressed:
[self performSelector:#selector(timeout:) withObject:nil afterDelay:30.0];
The issue comes in when I wanted to cancel this from a background thread:
[NSObject cancelPreviousPerformRequestsWithTarget:self];
I did this and it didn't cancel, it still calls timeout after 30 second. So my question, is there a way to cancel this from the background thread?

From the documentation, 'This method removes perform requests only in the current run loop, not all run loops.' That means that you have to call cancelPreviousPerformRequestsWithTarget on the main thread. Use performSelectorOnMainThread:withObject:waitUntilDone: from your thread to schedule a call to cancelPreviousPerformRequestsWithTarget on the main thread.
It's a roundabout way of doing things, but should work.
Edit to show example:
The easiest way is to use a helper method:
-(void)cancelTimeout
{
[NSObject cancelPreviousPerformRequestsWithTarget:self];
}
Then on your background thread call this when you want to cancel the timeout:
[self performSelectorOnMainThread:#selector(cancelTimeout) withObject:nil waitUntilDone:NO];

You can use NSTimer to call method after some time and invalidate if you want

Related

How can I cancel an NSOperation in the same thread that the operation?

When I cancel an NSOperation (when user presses a button) cancel method is called from the main thread, but evidently the operation is running in another thread.
So, to avoid race conditions when I change _isExecuting and _isFinished, I think cancel (or at least its logic) should be called from the same thread that the NSOperation. Apart from that, when user cancels it, several files are deleted and it takes time. Because cancel is called from main thread, all the app becomes unresponsive for a while, which is ugly.
How can I execute cancel code in the same thread that the current NSOperation?
I tried this in cancel (similar to what I saw in ASIHTTPRequest):
if (_operationThread) {
[self performSelector:#selector(cancelOnRequestThread) onThread:_operationThread withObject:nil waitUntilDone:NO];
} else {
[self cancelOnRequestThread];
}
And _operationThread is setted in start method using:
_operationThread=[NSThread currentThread];
But it doesn't work.
Any idea or suggestion?
Note: I use concurrent operations, so I use start instead of main.
Thanks a lot for help.
Ricardo.
It's fine to call cancel on an NSOperation from the main thread. The cancel method is thread-safe.
That shouldn't cause any blocking on your main thread because the cancel method itself shouldn't be doing any work. If you have overridden the cancel method of your operation to delete files, etc then that is the wrong approach. You shouldn't override the cancel method, instead just check the isCancelled method at regular points within the operation's main method (e.g. inside any tight loops) and then return from main early if isCancelled returns YES, which will then cancel the operation on the same thread as the rest of the execution.
If that's how you've implemented it already and you're still having performance issues, is it possible that your operation is not really running on a background thread at all? For example if you've added it to the queue returned by [NSOperationQueue mainQueue] then that's actually running on the main application thread.

How can I cancel or stop thread when back button is pressed?

I have been working with thread since last few days.I want to stop my thread when I press back button in navigation bar.But I couldn't find the solution to stop this background thread.If anybody know then please help me.
If you have done like this to run a function in background
i.e
[self performSelectorInBackground:#selector(myFunction) withObject:nil];
then to cancel it you can use this code
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(myFunction) object:nil];
You can subclass NSOperation and poll the isCancelled property to stop your thread from running.

UI update in selector

I perform this selector in my application:
- (void) doFilter:(UIButton*)button {
[activityIndicator startAnimating];
[self disableButtons];
// ...
// some actions
// ...
sleep(2);
[self enableButtons];
[activityIndicator stopAnimating];
}
when user clicks on button. activityIndicator is UIAtivityIndicatorView. But I don't see any activity indicators while this code is performing. How can I fix it?
Firstly, you should never ever use sleep on the main thread. It blocks your entire app and the user can't do anything for that time.
Secondly, the UI is not updated until your code returns control to the run loop. So whenever you call startAnimating and stopAnimating in the same method without returning to the run loop in between, you can be sure that nothing will happen in the UI (same with disableButtons and enableButtons).
Solution: call startAnimating and disableButtons. Then start the tasks you have to perform in the background so that the UI is not blocked. You can use NSOperation, performSelectorInBackground:..., Grand Central Dispatch etc. for that. Finally, when the long task is finished, have it call another method on the main thread which then calls stopAnimating and enableButtons.

Performselector not call in NSThread

I have a problem that i want to call a function when one of my functions that is running into a seperate thread comes to an end:
[NSThread detachNewThreadSelector:#selector(fetchFeaturedFreeApps) toTarget:self withObject:nil];
here is my fetchFeaturedFreeApps function
-(void)fetchFeaturedFreeApps
{
////all my code
[self performSelector:#selector(closeView) withObject:nil afterDelay:4.0];
}
My problem is that the close view methods doesnt run after the 4 seconds.
Hoew if i call the fetchFeaturedFreeApps method with perform selector then my closeview metod is called properly.
Your valuable help is highly appreciated.
You want to run any UI or view update code in a selector that runs on the main thread, not in a background thread. Use -performSelectorOnMainThread:withObject:waitUntilDone: and place a timer in that selector to fire after four seconds, which closes your view.

performSelectorOnMainThread works but performSelector doesn't why?

I have a selector and target, and calls the method like this
[target performSelectorOnMainThread:(SEL)selector withObject:nil waitUntilDone:FALSE];
But after I changed it to this, it doesn't work
[target performSelector:(SEL)selector withObject:nil afterDelay:0];
Any ideas?
I don't want to perform that task on the main thread because it lags the UI.
By doesn't work I mean that it simply doesn't call the method. I have it im debu mode in simulator and confirmed that it was not called.
I assume you're sending the message from another than the main thread. Cocoa just builds a run loop for the main thread, for other threads you have to build one yourself. The method performSelector:withObject:afterDelay: schedules the message for the next pass through the run loop. So if there is none, the message will not be sent.
For your case, why don't you just send [target performSelector:selector withObject:nil];? You dont need a run loop for that and the message will be sent immediately (on the same thread).