我希望在长任务运行时忽略按钮的所有触摸事件。
- (void)buttonAction{
NSLog(@"click!");
button.enabled = NO;
[self longTask];
}
- (void)longTask{
NSLog(@"task begin!");
sleep(5);
NSLog(@"task finished!");
button.enabled = YES;
}
在longTask期间,我再次点击按钮,它确实没有任何反应。但是,当longTask完成时,它会自动响应click事件并再次执行longTask! 当按钮的启用值为“NO”时,我点击了多少次,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,启用的值是'YES'?
感谢任何帮助!
答案 0 :(得分:3)
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!");
}
请注意,当您这样做时,您的所有用户界面都不会被阻止,只会禁用所需的按钮。
正如@Erik Godard所说,在执行此类任务时,您应该考虑使用某种UI反馈。您可以在将按钮的已启用属性设置为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 :(得分:1)
这里有几个问题。
最后,如果您仍想继续使用此方法,则可以声明一个标志,用于定义是否应调用longTask。您可以创建一个私有实例变量
BOOL shouldCall;
第一次调用longTask时,将其设置为NO。 longTask完成后,再次将其更改为yes。您可以将此与.hidden结合使用来控制按钮的UI。
正如@LucasEduardo指出的那样,除非你摆脱睡眠,否则三种解决方法将无效,所以无视这一点。
答案 2 :(得分:0)
感谢@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!