如何在Swift中创build延迟?

我想暂停我的应用程序在某一点上。 换句话说,我希望我的应用程序执行代码,但是在某个时候,暂停4秒,然后继续执行其余的代码。 我怎样才能做到这一点?

我正在使用Swift。

如果从UI线程调用,将会locking程序,而不是睡眠,请考虑使用NSTimer或调度计时器。

但是,如果你真的需要在当前线程中的延迟:

 ... { sleep(4) } 

这使用UNIX的sleepfunction。

使用dispatch_after块在大多数情况下比使用sleep(time)更好,因为执行睡眠的线程被阻止从事其他工作。 当使用dispatch_after ,工作的线程不会被阻塞,因此可以在此期间做其他工作。
如果您正在处理应用程序的主线程,那么使用sleep(time)对于您的应用程序的用户体验来说是不利的,因为在此期间UI没有响应。

计划后调度一个代码块的执行,而不是冻结线程:

Swift≥3.0

 DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: { // Put your code which should be executed with a delay here }) 

Swift <3.0

 let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC)) dispatch_after(time, dispatch_get_main_queue()) { // Put your code which should be executed with a delay here } 

我同意dispatch_after勒使用dispatch_after在这里是一个不错的select 。 但是你可能不喜欢GCD调用,因为它们很烦人 。 相反,你可以添加这个方便的帮手

 public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) { let dispatchTime = DispatchTime.now() + seconds dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure) } public enum DispatchLevel { case main, userInteractive, userInitiated, utility, background var dispatchQueue: DispatchQueue { switch self { case .main: return DispatchQueue.main case .userInteractive: return DispatchQueue.global(qos: .userInteractive) case .userInitiated: return DispatchQueue.global(qos: .userInitiated) case .utility: return DispatchQueue.global(qos: .utility) case .background: return DispatchQueue.global(qos: .background) } } } 

现在你只需要像下面这样在后台线程上延迟你的代码

 delay(bySeconds: 1.5, dispatchLevel: .background) { // delayed code that will run on background thread } 

延迟主线程上的代码更简单:

 delay(bySeconds: 1.5) { // delayed code, by default run in main thread } 

如果你更喜欢一个框架 ,也有一些更方便的function,然后检查HandySwift 。 您可以通过Carthage将其添加到您的项目中然后像上面的示例一样使用它:

 import HandySwift delay(by: .seconds(1.5)) { // delayed code } 

的NSTimer

@nneonneo的答案build议使用NSTimer但没有显示如何去做。 这是基本的语法:

 let delay = 0.5 // time in seconds NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(myFunctionName), userInfo: nil, repeats: false) 

这是一个非常简单的项目,以显示如何使用它。 当一个button被按下时,它会启动一个定时器,在延迟半秒后调用一个function。

 import UIKit class ViewController: UIViewController { var timer = NSTimer() let delay = 0.5 // start timer when button is tapped @IBAction func startTimerButtonTapped(sender: UIButton) { // cancel the timer in case the button is tapped multiple times timer.invalidate() // start the timer timer = NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) } // function to be called after the delay func delayedAction() { print("action has started") } } 

使用dispatch_time (如Palle的答案 )是另一个有效的选项。 但是很难取消 。 有了NSTimer ,在事件发生之前取消一个延迟的事件,所有你需要做的就是调用

 timer.invalidate() 

不build议使用sleep ,特别是在主线程上,因为它会停止线程上的所有工作。

在这里看到我更全面的答案。

你也可以用Swift 3来做到这一点。

像这样延迟后执行function。

 override func viewDidLoad() { super.viewDidLoad() self.perform(#selector(performAction), with: nil, afterDelay: 2.0) } func performAction() { //This function will perform after 2 seconds print("Delayed") } 

swift 3.0中不同方法之间的比较

睡觉

此方法没有回叫。 将代码直接放在此行后面4秒钟内执行。 它会阻止用户像testingbutton一样迭代UI元素,直到时间消失。 尽pipe睡眠时button有些冻结,但活动指示灯等其他元素仍然在旋转而没有冻结。 睡眠期间不能再次触发这个动作。

 sleep(4) print("done")//Do stuff here 

在这里输入图像说明

2.调度,执行和定时器

这三种方法的工作原理类似,都是在后台线程上运行,只是语法不同,function略有不同。

调度通常用于在后台线程上运行某些内容。 它具有callback作为函数调用的一部分

 DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: { print("done") }) 

Perform实际上是一个简化的计时器。 它用延迟设置一个计时器,然后通过select器触发该function。

 perform(#selector(callback), with: nil, afterDelay: 4.0) func callback() { print("done") }} 

最后,定时器还提供了重复callback的能力,这在这种情况下是无用的

 Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false) func callback() { print("done") }} 

对于所有这三种方法,当您点击button触发它们时,UI将不会冻结,您可以再次点击它。 如果再次点击该button,则会设置另一个计时器,并且该callback将被触发两次。

在这里输入图像说明

结论是

四种方法都不能仅仅靠自己的工作。 sleep将禁止用户交互,所以屏幕“ 冻结 ”(而不是实际),并导致不良的用户体验。 其他三种方法不会冻结屏幕,但您可以多次触发它们,而且大多数情况下,您希望等到您接听电话后再允许用户再次拨打电话。

所以一个更好的devise将使用三种asynchronous方法之一与屏幕截图。 当用户点击button时,用一个半透明的视图覆盖整个屏幕,顶部有一个旋转的活动指示器,告诉用户正在处理button点击。 然后删除callback函数中的视图和指示符,告诉用户操作处理正确等。

在Swift 3.0中尝试下面的实现

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

用法

 delayWithSeconds(1) { //Do something } 

要创build一个简单的时间延迟,您可以导入达尔文,然后使用睡眠(秒)做延迟。 但是,这只需要一整秒钟,所以为了更精确的测量,您可以导入达尔文,并使用百万分之一秒(usleep)进行非常精确的测量。 为了testing这个,我写道:

 import Darwin print("This is one.") sleep(1) print("This is two.") usleep(400000) print("This is three.") 

打印,然后等待1秒,打印,然后等待0.4秒,然后打印。 所有按预期工作。

这是最简单的

  delay(0.3, closure: { // put her any code you want to fire it with delay button.removeFromSuperview() })