CancelPreviousPerformRequestsWithTarget не отменяет выдающуюся выполненную функциюSelector: withDelay

Я использую UIWebView и не хочу, чтобы панель навигации отображалась, если пользователь не нажимает нигде на экране, который не является ссылкой. Поэтому у меня есть этот код для отображения панели навигации после задержки:

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

Я не звоню showNavigationBar сразу же, когда вызывается обработчик крана, потому что пользователь может использовать ссылку, в этом случае вызывающий дескриптор вызывается до UIWebView shouldStartLoadWithRequest, поэтому, если я спрятал навигационную панель в shouldStartLoadWithRequest он мгновенно мигнет на экран. Поэтому вместо этого я устанавливаю его для отображения после задержки, которая дает время для выполнения следующего кода в shouldStartLoadWithRequest (и если пользователь не нажал на ссылку shouldStartLoadWithRequest, не вызывается и отображается панель навигации, так как это должно быть в этом случае).

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

Однако это не работает, я увеличил время задержки до нескольких секунд и могу подтвердить, что cancelPreviousPerformRequestWithTarget получает вызов до отображения панели навигации, но когда указанное время истекает, отображается панель. cancelPreviousPerformRequestWithTarget не имеет эффекта.

Кто-нибудь знает, почему он не работает?

Ответ 1

В документации этого метода + (void)cancelPreviousPerformRequestsWithTarget:(id)aTarget selector:(SEL)aSelector object:(id)anArgument есть следующее предложение:

Этот метод удаляет запросы на выполнение только в текущем цикле выполнения, а не во всех циклах выполнения.

Если я правильно его интерпретирую, это будет означать, что вам нужно отменить действие в том же цикле выполнения, в котором вы его запустили. Что явно не то, что вы хотите сделать.

Чтобы обойти это, нужно иметь флаг, который showNavigationBar должен будет проверить, чтобы увидеть, следует ли ему продолжить или прервать.

Ответ 2

Ваше выполнение не соответствует вашему отмене. В выполнении вы передаете себя как объект:

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

В отмене вы передаете ноль как объект:

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

Они не совпадают, поэтому отложенное выполнение не следует отменять.

Ответ 3

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

Это сработало для меня;)

Ответ 4

Не знаю почему, но для меня это работает как шарм.

dispatch_async(dispatch_get_main_queue(), ^{

        [NSObject cancelPreviousPerformRequestsWithTarget:self];
    });