Xcode Objective-C | iOS:延迟函数/ NSTimer 帮助?

33

我正在开发我的第一个iOS应用程序,需要帮助...

目前只有一个简单的程序,我有大约9个按钮,当我按下第一个或任何一个按钮时,我只想让第一个按钮突出显示60毫秒,取消突出显示,然后第二个按钮突出显示,等待60毫秒,取消突出显示,并一直进行下去,直到所有按钮都亮起来,就像移动的LED灯。

我尝试了使用sleep/usleep,但是一旦该休眠持续时间结束,好像就会跳过突出显示/取消突出显示操作。

例如:

- (void) button_circleBusy:(id)sender{
firstButton.enabled = NO;
sleep(1);
firstButton.enabled = YES;

对于其它的按钮也是这样。它确实有延迟,但不会延迟 "firstButton.enabled = NO;" 这一步。我为每个按钮的 "禁用状态" 都准备了一张图片,但从来没有看到过。

非常感谢任何帮助!我已经研究了 NSTimer,但不确定如何实现。

谢谢。

-Paul

7个回答

51

sleep 不起作用,因为显示屏只能在主线程返回系统后更新。NSTimer是解决此问题的方法。为此,您需要实现将由计时器调用以更改按钮的方法。例如:

- (void)button_circleBusy:(id)sender {
    firstButton.enabled = NO;
    // 60 milliseconds is .06 seconds
    [NSTimer scheduledTimerWithTimeInterval:.06 target:self selector:@selector(goToSecondButton:) userInfo:nil repeats:NO];
}
- (void)goToSecondButton:(id)sender {
    firstButton.enabled = YES;
    secondButton.enabled = NO;
    [NSTimer scheduledTimerWithTimeInterval:.06 target:self selector:@selector(goToThirdButton:) userInfo:nil repeats:NO];
}
...

嘿,ughoavgfhw,感谢您的回复。好的,这似乎很容易!但是我还有另一个名为button_killAll()的函数,它应该在0.06秒内禁用所有内容。我注意到NSTimer使用selector:@selector(goToSecondButton:),如果我不想去另一个函数,只是延迟禁用0.06秒怎么办?我想另一种提问方式是,一旦我到达最后一个要突出显示/禁用的按钮,由于我不希望该循环结束,我应该放什么? - Retro

47
int64_t delayInSeconds = 0.6;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
     do something to the button(s)
});

你太棒了!谢谢,我已经寻找这个很久了! - Finn Gaida
1
很有用!+1和谢谢 - Jayprakash Dubey
我也喜欢这个语法,谢谢你节省了我的时间。无论如何,如果延迟时间少于一秒钟,应该使用delayInSeconds * NSEC_PER_MSEC并将延迟值更改为600。 - majorl3oat
这比其他答案中的任何代码都要好 +1。 - Jesus

29

少即是多。

[NSThread sleepForTimeInterval:0.06];

Swift:

Thread.sleep(forTimeInterval: 0.06)

好多了。谢谢。 - user246672
1
只有在“可读代码比难懂的代码更好”之后,这个答案的更重要的支持者才出现了。 - Jesse the Game
我喜欢少代码,但它不允许屏幕按照提问者的要求更新。在NSThread sleepForTimeInterval:的文档中,线程被阻塞时不会发生运行循环处理 - slothbear
2
睡眠会阻塞线程。因此会产生副作用,对于UI线程没有用处。 - Karsten

25

可以稍微简单一点的方法是使用performSelector: withObject: afterDelay:, 它会为您设置NSTimer对象,并且可以很容易地取消。

因此,继续上一个例子,代码如下:

[self performSelector:@selector(goToSecondButton) withObject:nil afterDelay:.06];

在文档中可以获得更多信息


我更喜欢这个解决方案。performSelector可以将冗长性降至最低。 - Brent Faust

16

尝试

NSDate *future = [NSDate dateWithTimeIntervalSinceNow: 0.06 ];
[NSThread sleepUntilDate:future];

3

我想补充一下Avner Barr的答案。当使用int64时,当我们超过1.0值时,该函数似乎会有不同的延迟。因此,我认为在这一点上,我们应该使用NSTimeInterval。

因此,最终代码如下:

NSTimeInterval delayInSeconds = 0.05;

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

//do your tasks here

});

0
[NSTimer scheduledTimerWithTimeInterval:.06 target:self selector:@selector(goToSecondButton:) userInfo:nil repeats:NO];

这是最好的选择。使用sleep(15);会导致用户无法执行任何其他操作。使用以下函数,您可以将goToSecondButton替换为适当的选择器或命令,也可以来自框架。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接