Xcode 如何在Swift中创建延迟?

Xcode 如何在Swift中创建延迟?,xcode,swift,delay,Xcode,Swift,Delay,我想在某个特定点暂停我的应用程序。换句话说,我希望我的应用程序执行代码,但在某一点上,暂停4秒钟,然后继续执行其余的代码。我该怎么做 我使用SWIFT.而不是一个睡眠,它会锁定你的程序,如果从UI线程调用,考虑使用 NSTIMER < /代码>或调度定时器。 但是,如果在当前线程中确实需要延迟: do { sleep(4) } 这使用了UNIX中的函数。在块之后使用分派\u在大多数情况下比使用睡眠(时间)要好,因为执行睡眠的线程被阻止执行其他工作。使用dispatch\u after时

我想在某个特定点暂停我的应用程序。换句话说,我希望我的应用程序执行代码,但在某一点上,暂停4秒钟,然后继续执行其余的代码。我该怎么做


我使用SWIFT.

而不是一个睡眠,它会锁定你的程序,如果从UI线程调用,考虑使用<代码> NSTIMER < /代码>或调度定时器。

但是,如果在当前线程中确实需要延迟:

do {
    sleep(4)
}

这使用了UNIX中的函数。

在块之后使用
分派\u在大多数情况下比使用
睡眠(时间)
要好,因为执行睡眠的线程被阻止执行其他工作。使用
dispatch\u after
时,所处理的线程不会被阻塞,因此它可以同时执行其他工作
如果您正在处理应用程序的主线程,则使用
睡眠(时间)
对应用程序的用户体验有害,因为在此期间UI没有响应。

调度代码块的执行而不是冻结线程后分派:

敏捷的≥ 3 Swift<3.0 @nneonneo的回答建议使用
NSTimer
,但没有说明如何操作。这是基本语法:

let delay = 0.5 // time in seconds
NSTimer.scheduledTimerWithTimeInterval(delay, target: self, selector: #selector(myFunctionName), userInfo: nil, repeats: false)
下面是一个非常简单的项目,展示如何使用它。当按下一个按钮时,它会启动一个计时器,该计时器将在半秒的延迟后调用一个函数

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\u time
(如中所示)是另一个有效选项。然而,事实并非如此。使用
NSTimer
,要在延迟事件发生之前取消它,只需调用

timer.invalidate()
不建议使用
sleep
,尤其是在主线程上,因为它会停止在线程上执行的所有工作


请参阅以获取更完整的答案。

我同意Palle的观点,即在
之后使用
dispatch\u是一个不错的选择。但是你可能不喜欢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
}

如果您更喜欢同样具有一些更方便功能的框架,请签出。您可以通过将其添加到项目中,然后像上面的示例一样使用它:

import HandySwift    

delay(by: .seconds(1.5)) { 
    // delayed code
}
这是最简单的

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

在Swift 3.0中尝试以下实现

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


您也可以使用Swift 3执行此操作

在延迟后执行此功能,如下所示

override func viewDidLoad() {
    super.viewDidLoad()

    self.perform(#selector(ClassName.performAction), with: nil, afterDelay: 2.0)
}


     @objc func performAction() {
//This function will perform after 2 seconds
            print("Delayed")
        }

要创建简单的时间延迟,可以导入Darwin,然后使用sleep(秒)进行延迟。不过,这只需要几秒钟,所以对于更精确的测量,您可以导入达尔文并使用usleep(百万分之一秒)进行非常精确的测量。为了验证这一点,我写道:

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

打印,然后等待1秒,然后打印,然后等待0.4秒,然后打印。所有操作均按预期进行。

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

1。睡眠

此方法没有回调。将代码直接放在这行后面,以便在4秒内执行。它将阻止用户使用UI元素(如test按钮)进行迭代,直到时间过去。虽然当睡眠开始时,按钮有点冻结,但其他元素,如活动指示器,仍在不冻结地旋转。您不能在睡眠期间再次触发此操作

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

2。调度、执行和计时

self.delay(0.1, closure: {
   //execute code
})
这三种方法的工作原理类似,它们都在后台线程上运行,并带有回调,只是语法不同,功能略有不同

Dispatch通常用于在后台线程上运行某些东西。它将回调作为函数调用的一部分

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
    print("done")
})
Perform实际上是一个简化的计时器。它设置一个带有延迟的计时器,然后通过选择器触发该功能

perform(#selector(callback), with: nil, afterDelay: 4.0)

func callback() {
    print("done")
}}
最后,计时器还提供了重复回调的功能,这在本例中没有用处

Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false)


func callback() {
    print("done")
}}
对于所有这三种方法,当您单击按钮触发它们时,UI不会冻结,您可以再次单击它。如果再次单击该按钮,将设置另一个计时器,并将触发两次回调

总之

这四种方法中没有一种单靠它们自己就足够有效
sleep
将禁用用户交互,因此屏幕“冻结”(实际上并非如此)并导致糟糕的用户体验。其他三种方法不会冻结屏幕,但您可以多次触发它们,大多数情况下,您希望等到收到回拨后再允许用户再次拨打电话


因此,更好的设计是使用三种异步方法中的一种来屏蔽。当用户点击按钮时,用半透明视图覆盖整个屏幕,顶部有旋转活动指示器,告诉用户正在处理按钮点击。然后移除回调函数中的视图和指示器,告诉用户操作已正确处理,等等。

如果需要设置小于一秒的延迟,则无需设置.seconds参数。我希望这对某人有用

DispatchQueue.global(qos: .background).async {
    sleep(4)
    print("Active after 4 sec, and doesn't block main")
    DispatchQueue.main.async{
        //do stuff in the main thread here
    }
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: {
        // your code hear
})

在Swift 4.2和Xcode 10.1中

您总共有4种延迟方式。在这些中,选项1最好在一段时间后调用或执行函数。sleep()是使用最少的case

选项1。

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.yourFuncHere()
}
//Your function here    
func yourFuncHere() {

}
perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)

//Your function here  
@objc func yourFuncHere2() {
    print("this is...")
}
Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)

//Your function here  
@objc func yourFuncHere3() {

}
sleep(5)
选项2。

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.yourFuncHere()
}
//Your function here    
func yourFuncHere() {

}
perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)

//Your function here  
@objc func yourFuncHere2() {
    print("this is...")
}
Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)

//Your function here  
@objc func yourFuncHere3() {

}
sleep(5)
选项3。

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.yourFuncHere()
}
//Your function here    
func yourFuncHere() {

}
perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)

//Your function here  
@objc func yourFuncHere2() {
    print("this is...")
}
Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)

//Your function here  
@objc func yourFuncHere3() {

}
sleep(5)
选项4。

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.yourFuncHere()
}
//Your function here    
func yourFuncHere() {

}
perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)

//Your function here  
@objc func yourFuncHere2() {
    print("this is...")
}
Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)

//Your function here  
@objc func yourFuncHere3() {

}
sleep(5)

如果要在一段时间后调用函数以执行某些操作,请不要使用sleep

如果代码已在后台线程中运行,请使用以下命令暂停线程:
thread.sleep(forTimeInterval:)

例如:

DispatchQueue.global(qos: .userInitiated).async {

    // Code is running in a background thread already so it is safe to sleep
    Thread.sleep(forTimeInterval: 4.0)
}
(请参阅其他答案,以了解您的建议。)