【问题标题】:How can I delay a method call for 1 second?如何将方法调用延迟 1 秒?
【发布时间】:2010-10-29 13:44:10
【问题描述】:

有没有简单的方法将方法调用延迟 1 秒?

我有一个UIImageView,它对触摸事件做出反应。当检测到触摸时,应用程序中会出现一些动画。一秒钟后,我想调用另一个方法。在这种情况下,我不能使用animationDidStop 选择器。

【问题讨论】:

  • 当然有几种方法可以做到这一点,其中一种可能是简单地使用 sleep() 将程序/线程挂起几毫秒,但是我认为您可能想告诉我们您到底想通过这样做来完成什么?我的意思是,你的实际问题是什么?延迟方法调用的想法似乎是一种“解决方案”,说实话听起来不太好。所以,请告诉我们更多关于您的想法的情况。

标签: ios objective-c iphone cocoa-touch uikit


【解决方案1】:

Swift 2.x

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
 dispatch_after(delayTime, dispatch_get_main_queue()) {
 print("do some work")
}

Swift 3.x --&-- Swift 4

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
    print("do some work")
}

或传递escaping closure

func delay(seconds: Double, completion: @escaping()-> Void) {
    DispatchQueue.main.asyncAfter(deadline: .now() + seconds, execute: completion)
}

【讨论】:

    【解决方案2】:

    在 Swift 3 中使用

    perform(<Selector>, with: <object>, afterDelay: <Time in Seconds>)
    

    【讨论】:

      【解决方案3】:

      你也可以使用块

      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
          [object method]; 
      });
      

      大多数情况下,您会希望使用 dispatch_get_main_queue,但如果方法中没有 UI,您可以使用 global queue

      编辑:

      Swift 3 版本:

      DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
          object.method()
      }
      

      同样,DispatchQueue.global().asyncAfter(... 也可能是一个不错的选择。

      【讨论】:

      • 发现这个解决方案在混合直接 C 和 ObjC 时比 performSelector 更容易
      • 不幸的是 dispatch_get_current_queue 自 iOS6 以来已被弃用
      • 更新为使用 dispatch_get_main_queue 而不是 dispatch_get_current_queue
      • Xcode 现在会自动完成这个,只需开始输入dispatch_after 并按回车键
      • 特别是现在 Xcode 在输入 dispatch_after 时会自动完成这个,这确实是一种超级简单的方法,而且您可以将属性传递给您正在调用的方法,这很棒。跨度>
      【解决方案4】:

      已检查的解决方案中有一个 Swift 3 解决方案:

      self.perform(#selector(self.targetMethod), with: self, afterDelay: 1.0)
      

      还有方法

      @objc fileprivate func targetMethod(){
      
      }
      

      【讨论】:

        【解决方案5】:

        注意:这将暂停您的整个线程,而不仅仅是一种方法。
        在调用您的方法之前调用 sleep/wait/halt 1000 ms?

        Sleep(1000); // does nothing the next 1000 mSek
        
        Methodcall(params); // now do the real thing
        

        编辑:上述答案适用于一般问题“如何将方法调用延迟 1 秒?”,这是在回答时提出的问题(实际上答案是在原始问题的 7 分钟内给出的题 :-))。 当时没有提供有关该语言的信息,所以请不要再抱怨使用睡眠 i XCode og 缺少类的正确方法......

        【讨论】:

        • 只在当前线程中,其他线程会继续运行。
        • 天啊。我明白为什么这被否决了几次,但到底是谁在 -27 看到了这个并决定需要另一个?是否 -3 或其他东西没有说明问题。为什么不直接编辑答案说“这将暂停你的整个线程”或其他内容,而不是对人们投反对票?
        • 如果你只想暂停整个线程怎么办?如果它带有一个体面的警告,这似乎是一个有效的选择。
        • @AlbertRenshaw 我完全同意你的看法。我在这里和它的 35 次起伏,我放弃了他。我看到更像是对低声誉用户进行如此严重的攻击。没有人会做任何编辑或指定任何东西。我今天看到一个答案是真的淹死了。该人所做的唯一错误是他/她用客观的 c 语言在一个快速的问题下回答。如果这是一个巨大的错误,我想在客观 c 问题下显示这么多快速的答案。
        【解决方案6】:

        最好的办法是:

        [self performSelector:@selector(YourFunctionName) 
                   withObject:(can be Self or Object from other Classes) 
                   afterDelay:(Time Of Delay)];
        

        您也可以将 nil 作为 withObject 参数传递。

        例子:

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

        【讨论】:

        • 你为什么要把self传给self?
        • 为什么要将变量传递给采用零参数的方法?
        【解决方案7】:

        已经有很多答案,而且都是正确的。如果您想使用dispatch_after,您应该寻找包含在右下角Code Snippet Library 内的sn-p(您可以在其中选择UI 元素)。

        所以你只需要通过在代码中编写dispatch来调用这个sn-p:

        【讨论】:

          【解决方案8】:

          你可以这样做

          [self performSelector:@selector(MethodToExecute) withObject:nil afterDelay:1.0 ];
          

          【讨论】:

            【解决方案9】:
            performSelector:withObject:afterDelay:
            

            Document Reference

            【讨论】:

            • 有什么方法可以处理被调用方法的返回值吗?或者如果我想从中获取一些信息,是否需要设置它来修改参数?
            • 如果有人有兴趣如何取消预定的通话:[NSObject cancelPreviousPerformRequestsWithTarget:yourTarget selector:aSelector object: anArgument];
            【解决方案10】:

            您还可以:

            [UIView animateWithDuration:1.0
                             animations:^{ self.view.alpha = 1.1; /* Some fake chages */ }
                             completion:^(BOOL finished)
            {
                NSLog(@"A second lapsed.");
            }];
            

            在这种情况下,您必须对某些视图进行一些更改才能使动画正常工作。它确实很hacky,但我喜欢基于块的东西。或者在下面总结@mcfedr 的答案。


            waitFor(1.0, ^
            {
                NSLog(@"A second lapsed");
            });
            

            typedef void (^WaitCompletionBlock)();
            void waitFor(NSTimeInterval duration, WaitCompletionBlock completion)
            {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, duration * NSEC_PER_SEC),
                               dispatch_get_main_queue(), ^
                { completion(); });
            }
            

            【讨论】:

            • 不确定,但我认为您建议的第一个选项可能具有用户应该注意的副作用,例如阻止用户在部分 UI 上进行交互。我的直觉是它也会导致一些不必要的 CPU 或其他资源消耗,但我没有检查。
            【解决方案11】:

            您可以在调用 0.1 秒延迟方法之后使用执行选择器来执行以下代码。

            [self performSelector:@selector(InsertView)  withObject:nil afterDelay:0.1]; 
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-10-24
              • 2012-04-25
              • 1970-01-01
              • 1970-01-01
              • 2012-08-19
              相关资源
              最近更新 更多