Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

cancelPreviousPerformRequestsWithTarget not cancelling an outstanding performSelector:withDelay

Tags:

ios

I am using a UIWebView and don't want the navigation bar to appear unless the user taps anywhere on the screen that isn't a link. So I have this code to display the navigation bar after a delay:

- (void)handleTapGesture:(UITapGestureRecognizer *)sender  
{      
.... 
[self performSelector:@selector(showNavigationBar) withObject:self afterDelay:0.2]; 
}

I'm not calling showNavigationBar immediately when the tap handler is invoked because the user might have tapped on a link in which case the tap hander is called before UIWebView shouldStartLoadWithRequest, so if I hid the navigation bar in shouldStartLoadWithRequest it would flash momentarily onto the screen. So instead I set it to display after a delay which gives time for the following code to execute within shouldStartLoadWithRequest (and if the user didn't tap on a link shouldStartLoadWithRequest isn't called and the navigation bar is displayed, as it should be in that case).

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType  
{ 
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showNavigationBar) object:nil];
...

However this isn't working, I've increased the delay time to several seconds and can confirm cancelPreviousPerformRequestWithTarget is getting called before the navigation bar has been displayed, but when the specified time elapses the bar displays. cancelPreviousPerformRequestWithTarget is having no effect.

Does anybody know why its not working?

like image 757
Gruntcakes Avatar asked Jan 02 '12 05:01

Gruntcakes


2 Answers

In the documentation of that + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument method there is this sentence :

This method removes perform requests only in the current run loop, not all run loops.

If I'm interpreting it correctly it would mean that you need to cancel your action in the same run loop that you launched it. Which is clearly not what you want to do.

A way to go around this would be to have a flag that showNavigationBar would have to check to see if it should proceed or abort.

like image 182
Vincent Bernier Avatar answered Oct 20 '22 07:10

Vincent Bernier


Your perform doesn't match your cancel. In the perform you're passing self as the object:

[self performSelector:@selector(showNavigationBar) withObject:self afterDelay:0.2]; 

In the cancel you're passing nil as the object:

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(showNavigationBar) object:nil];

They don't match, so the delayed perform should not be canceled.

like image 37
Dave Batton Avatar answered Oct 20 '22 06:10

Dave Batton