在以下两行的执行之间增加延迟


78

我需要在(相同)函数的两行执行之间增加延迟。有什么有利的选择吗?

注意:我不需要两个不同的函数来执行此操作,并且延迟一定不会影响其他函数的执行。

例如:

line 1: [executing first operation];

line 2: Delay                        /* I need to introduce delay here */

line 3: [executing second operation];

任何帮助都是可观的。提前致谢...

Answers:


208

您可以使用gcd来执行此操作,而无需创建其他方法

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
  NSLog(@"Do some work");
});

您仍然应该问自己“我真的需要增加延迟吗”,因为它通常会使代码复杂化并导致竞争状况


2
向人们发出警告是正确的,但是如果您对需要等待具有固定处理时间的外部设备的控制器进行编码,则并非毫无意义。
user2161301 2015年

3
在搜索栏中写入内容时延迟HTTP请求怎么办?在输入时过滤结果?在请求过滤列表之前等待一秒钟,而不是向服务器查询用户点击的每个键,这听起来像我的废话。
亚历杭德罗·伊万

26

您可以使用以下NSThread方法:

[NSThread sleepForTimeInterval: delay];

但是,如果您在主线程上执行此操作,则会阻止该应用程序,因此只能在后台线程上执行此操作。


或在Swift

NSThread.sleepForTimeInterval(delay)

在Swift 3中

Thread.sleep(forTimeInterval: delay)

2
我认为这应该是根据问题要求接受的答案。
ACLima

1
@ACLima:对不起,“ sleepForTimeInterval”会使线程在给定的时间间隔内休眠,这可能会影响其他同时执行的函数。
克里希纳·拉吉·萨利姆

它的第二或钟表?
希瓦

20

此行在3秒钟后调用选择器secondMethod:

[self performSelector:@selector(secondMethod) withObject:nil afterDelay:3.0 ];

在您需要的延迟时间进行第二次操作时使用它。如果您有很多代码,请将其放在自己的方法中,然后使用调用该方法performSelector:。它不会像sleep

编辑:如果您不希望使用第二种方法,则可以添加一个类别,以便能够通过performSelector使用块:

@implementation NSObject (PerformBlockAfterDelay)

- (void)performBlock:(void (^)(void))block 
          afterDelay:(NSTimeInterval)delay
{
    block = [block copy];
    [self performSelector:@selector(fireBlockAfterDelay:) 
               withObject:block 
               afterDelay:delay];
}

- (void)fireBlockAfterDelay:(void (^)(void))block
{
    block();
}

@end

甚至更清洁:

void RunBlockAfterDelay(NSTimeInterval delay, void (^block)(void))
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay),
      dispatch_get_current_queue(), block);
}

6
OP明确声明他们不希望使用第二种方法:S
Paul.s

他可以添加类别,以便能够使用块具有performSelectorstackoverflow.com/questions/4007023/...
Sunkas

@Sunkas:感谢您的回答。但是我已经提到我不想添加第二个功能。
克里希纳·拉吉·萨利姆

3
使用该答案将为您提供一种在没有第二种方法的情况下延迟运行代码的干净方法。[self performBlock:^{ your_code } afterDelay:0.1];
2014年

4
如果OP不愿意添加另一种方法,则应该解释原因,因为这是使用设计好的工具的一种很好的方法。方法不好吗?他们是按(无效)付款吗?
使用者

8

我有几个基于回合的游戏,需要AI在回合之前(以及在回合之间的步骤之间)暂停。我确信还有其他更有用的情况,延迟是最好的解决方案。在Swift中:

        let delay = 2.0 * Double(NSEC_PER_SEC) 
        let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) 
        dispatch_after(time, dispatch_get_main_queue()) { self.playerTapped(aiPlayView) }

我只是回到这里查看Objective-C调用是否不同(我也需要将其添加到该调用中)。


4

如果您的目标是iOS 4.0+,则可以执行以下操作:

[executing first operation];
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    [executing second operation];
});

1
您是说iOS 4?大中央调度功能参考
Paul.s

3

如今,最方便的方法是:Xcode提供了一个代码片段来执行此操作,您只需输入延迟值以及希望在延迟后运行的代码即可。

  1. 单击+Xcode右上方的按钮。
  2. 搜索 after
  3. 它将仅返回1个搜索结果,这是所需的代码段(请参见屏幕截图)。双击它就可以了。

该屏幕快照说明了如何从Xcode本身获取片段


1

就像@Sunkas所写performSelector:withObject:afterDelay:dispatch_after一样,它是吊坠的缩写,因为它较短并且您具有正常的objective-c语法。如果需要将参数传递到要延迟的块,则可以通过参数传递参数withObject,然后在selector调用中将其接收:

[self performSelector:@selector(testStringMethod:) 
           withObject:@"Test Test" 
           afterDelay:0.5];

- (void)testStringMethod:(NSString *)string{
    NSLog(@"string  >>> %@", string);
}

如果仍要选择在主线程或当前线程上执行它,则可以使用一些特定的方法来指定它。苹果文档说明了这一点:

如果您希望在运行循环处于默认模式以外的其他模式时使消息出队,请改用performSelector:withObject:afterDelay:inModes:方法。如果不确定当前线程是否为主线程,则可以使用performSelectorOnMainThread:withObject:waitUntilDone:或performSelectorOnMainThread:withObject:waitUntilDone:modes:方法来确保选择器在主线程上执行。要取消排队的消息,请使用cancelPreviousPerformRequestsWithTarget:或cancelPreviousPerformRequestsWithTarget:selector:object:方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.