簡體   English   中英

在長時間的任務中忽略UIButton的touch事件

[英]Ignore UIButton's touch event in a long task time

我要忽略長時間運行任務時按鈕的所有觸摸事件。

- (void)buttonAction{
    NSLog(@"click!");
    button.enabled = NO;
    [self longTask];
}

- (void)longTask{
    NSLog(@"task begin!");
    sleep(5);
    NSLog(@"task finished!");
    button.enabled = YES;
}

在longTask時間內,我再次單擊該按鈕,實際上什么也沒有發生。 但是,當longTask完成時,它將自動響應單擊事件並再次執行longTask! 當按鈕的啟用值為“否”時,我單擊了多少次,longTask將執行多少次。

2013-08-20 09:24:49.478 AppName[2518:c07] click!
2013-08-20 09:24:49.479 AppName[2518:c07] task begin!
2013-08-20 09:24:54.481 AppName[2518:c07] task finished!
2013-08-20 09:24:54.482 AppName[2518:c07] click!
2013-08-20 09:24:54.482 AppName[2518:c07] task begin!
2013-08-20 09:24:59.484 AppName[2518:c07] task finished!

我試圖將userInteractionEnabled設置為NO,但結果相同。

當長時間執行任務而從不執行任務時,如何使其忽略所有觸摸事件? 換句話說,僅在啟用按鈕值為“是”時單擊按鈕時才執行longTask嗎?

謝謝你的幫助!

sleep只是凍結了負責所有UI交互的主線程。

您應該在后台執行所有冗長的任務,而使用GCD可以輕松實現這些任務。 只需執行以下操作,您就可以實現所需的功能:

- (void)buttonAction{

    NSLog(@"click!");
    button.enabled = NO;

    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
        //Background Thread

        [self longTask];

        dispatch_async(dispatch_get_main_queue(), ^(void){
             button.enabled = YES;
        });
    });
}

- (void)longTask{
    NSLog(@"task begin!");
    [NSThread sleepForTimeInterval:5];
    NSLog(@"task finished!");

} 

請注意,當您以這種方式進行操作時,將不再阻止所有UI,僅將禁用所需的按鈕。

正如@Erik Godard提到的那樣,您確實應該在執行此類任務時考慮使用某種UI反饋。 您可以在將按鈕的enabled屬性設置為NO的同一區域中啟動某個過程指示器,並在將該屬性設置為YES時停止它

沒有GCD的另一種方法是通過NSRunLoop的方法runUntilDate更改睡眠。 這樣,您的主線程也不會被阻塞,您將能夠實現所需的功能。

- (void)buttonAction{

    NSLog(@"click!");
    self.addCartButton.enabled = NO;
   [self longTask];
}

- (void)longTask{
    NSLog(@"task begin!");
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:5]];
    NSLog(@"task finished!");
   self.addCartButton.enabled = YES;
} 

兩種方法都經過測試,似乎可行。

這里有幾個問題。

  1. 首先,如果您正在執行任務,並且您不希望用戶在輸入任務時就能夠輸入,則應提供某種視覺指示器以告知用戶該應用程序尚未凍結。 僅禁用按鈕而不給出任何提示說明這對用戶體驗不利。 例如,您可以使用進度條或進度指示器來警告用戶任務已完成。
  2. 其次,如果您要執行的任務要花費大量時間(例如所建議的任務),則應考慮使用多線程。 有關的介紹,請參見此處 通常,您不想像這樣在主線程上執行計算密集型任務。
  3. 最后,如果您仍然想繼續使用此方法,則可以聲明一個標志,該標志定義是否應調用longTask。 您可以將一個私有實例變量

     BOOL shouldCall; 

首次調用longTask時,請將其設置為NO。 一旦longTask完成,將其再次更改為yes。 您可以將其與.hidden結合使用以控制按鈕的UI。

正如@LucasEduardo所指出的那樣,除非您擺脫睡眠,否則三分之二的替代方法都不會起作用,因此,請不要理會。

正如@Lucas Eduardo提到的那樣,在后台線程中執行長任務是最好的實現。 但是在某些情況下,該任務必須在主線程中執行,例如發送PDF或Web視圖或移動大圖像。 而且您仍然需要在運行時忽略觸摸事件。

感謝@Erik Godard的觀點。 當我必須在主線程中執行較長的任務時,必須設置BOOL值以響應觸摸事件。

- (void)buttonAction{
    NSLog(@"click!");
    [self longTask];
}

- (void)longTask{
    if (!isRunning) {
        button.enabled = NO;
        isRunning = YES;
        NSLog(@"task begin!");
        [NSThread sleepForTimeInterval:5];
        NSLog(@"task finished!");
        button.enabled = YES;
        [self performSelector:@selector(switchStatus) withObject:nil afterDelay:.5f];
    }
}

- (void)switchStatus{
    isRunning = NO;
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    isRunning = NO;
}

我在0.5秒的延遲后更改BOOL值,因為如果在button.enabled = YES之后立即設置isRunning = NO,則將再次執行longTask。 只需保留0.5秒的延遲,即可使觸摸事件繼續進行。 在此期間,isRunning的值仍等於YES,因此觸摸事件將被忽略。 0.5秒后,isRunning = NO,如果再次單擊該按鈕將觸發新的longTask。

2013-08-20 20:44:19.727 AppName[4005:c07] click!
2013-08-20 20:44:19.728 AppName[4005:c07] task begin!
2013-08-20 20:44:24.730 AppName[4005:c07] task finished!
2013-08-20 20:44:24.731 AppName[4005:c07] click!
2013-08-20 20:44:24.732 AppName[4005:c07] click!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM