如何在Swift 3、4和5中编写dispatch_after GCD ?

在Swift 2中,我能够使用dispatch_after来延迟使用中央调度的动作:

var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC)))
dispatch_after(dispatchTime, dispatch_get_main_queue(), {
// your function here
})

但这似乎不再编译自Swift 3。在现代Swift中,首选的写法是什么?

240253 次浏览

DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)

我强烈建议使用Xcode工具转换到Swift 3(编辑>转换>到当前Swift语法)。它帮我抓住了这个

语法很简单:

// to run something in 0.1 seconds


DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// your code here
}

注意,上面添加seconds作为Double的语法似乎是混淆的来源(特别是因为我们习惯添加nsec)。“以Double形式添加秒数”语法是可行的,因为deadline是一个DispatchTime,并且在幕后,有一个+操作符,它将接受一个Double并将这么多秒数添加到DispatchTime:

public func +(time: DispatchTime, seconds: Double) -> DispatchTime

但是,如果你真的想在DispatchTime中添加一个msec、μs或nsec的整数,你也可以在DispatchTime中添加DispatchTimeInterval。这意味着你可以:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
os_log("500 msec seconds later")
}


DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(1_000_000)) {
os_log("1m μs seconds later")
}


DispatchQueue.main.asyncAfter(deadline: .now() + .nanoseconds(1_500_000_000)) {
os_log("1.5b nsec seconds later")
}

由于DispatchTime类中+操作符的这个单独的重载方法,所有这些都无缝地工作。

public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime

有人问如何取消已分派的任务。为此,使用DispatchWorkItem。例如,这将启动一个将在5秒内触发的任务,或者如果视图控制器被解散并释放,它的deinit将取消该任务:

class ViewController: UIViewController {


private var item: DispatchWorkItem?


override func viewDidLoad() {
super.viewDidLoad()


item = DispatchWorkItem { [weak self] in
self?.doSomething()
self?.item = nil
}


DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: item!)
}


deinit {
item?.cancel()
}


func doSomething() { ... }


}

注意在DispatchWorkItem. xml中使用了[weak self]捕获列表。这对于避免强引用循环至关重要。还要注意的是,这不会执行先发制人的取消操作,而只是在任务还没有开始时停止它。但是如果它在遇到cancel()调用时已经开始,块将完成它的执行(除非你手动检查块内的isCancelled)。

斯威夫特4:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
// Code
}

对于目前的.seconds(Int).microseconds(Int).nanoseconds(Int)也可以使用。

如果你只是想把延迟函数

Swift 4 &5

func delay(interval: TimeInterval, closure: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
closure()
}
}

你可以这样使用它:

delay(interval: 1) {
print("Hi!")
}

在Swift 3发布后,@escaping也必须被添加

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

斯威夫特4

你可以在DispatchQueue上创建一个扩展,并在内部添加使用DispatchQueue asyncAfter函数的函数delay

extension DispatchQueue {
static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: closure)
}
}

和使用

DispatchQueue.delay(.milliseconds(10)) {
print("task to be done")
}

一个有点不同风格的公认答案。

斯威夫特4

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 + .milliseconds(500) +
.microseconds(500) + .nanoseconds(1000)) {
print("Delayed by 0.1 second + 500 milliseconds + 500 microseconds +
1000 nanoseconds)")
}

没有一个答案提到运行在非主线程上,所以添加我的2分。

主要的队列(主线程)上

let mainQueue = DispatchQueue.main
let deadline = DispatchTime.now() + .seconds(10)
mainQueue.asyncAfter(deadline: deadline) {
// ...
}

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) {
// ...
}

全球队列上(非主线程,基于指定的QOS)。

let backgroundQueue = DispatchQueue.global()
let deadline = DispatchTime.now() + .milliseconds(100)
backgroundQueue.asyncAfter(deadline: deadline, qos: .background) {
// ...
}

DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + .milliseconds(100), qos: .background) {
// ...
}

Swift 5及以上

DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
// code to execute
})