如何在Swift中创build延迟?
我想暂停我的应用程序在某一点上。 换句话说,我希望我的应用程序执行代码,但是在某个时候,暂停4秒,然后继续执行其余的代码。 我怎样才能做到这一点?
我正在使用Swift。
如果从UI线程调用,将会locking程序,而不是睡眠,请考虑使用NSTimer
或调度计时器。
但是,如果你真的需要在当前线程中的延迟:
... { sleep(4) }
这使用UNIX的sleep
function。
使用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() })