如何在 Swift 3、4 和 5 中编写 dispatch_after GCD? [英] How do I write dispatch_after GCD in Swift 3, 4, and 5?
问题描述
在 Swift 2 中,我能够使用 dispatch_after
使用大中央调度来延迟操作:
In Swift 2, I was able to use dispatch_after
to delay an action using grand central dispatch:
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 中编写它的首选方法是什么?
But this no longer seems to compile since Swift 3. What is the preferred way to write this in modern Swift?
推荐答案
语法很简单:
// to run something in 0.1 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// your code here
}
<小时>
注意,将 seconds
添加为 Double
的上述语法似乎是一个混乱的来源(尤其是因为我们习惯于添加 nsec)."add seconds as Double
" 语法是有效的,因为 deadline
是一个 DispatchTime
并且在幕后有一个 +
运算符,它将采用 Double
并将该秒数添加到 DispatchTime
:
Note, the above syntax of adding seconds
as a Double
seems to be a source of confusion (esp since we were accustomed to adding nsec). That "add seconds as Double
" syntax works because deadline
is a DispatchTime
and, behind the scenes, there is a +
operator that will take a Double
and add that many seconds to the DispatchTime
:
public func +(time: DispatchTime, seconds: Double) -> DispatchTime
但是,如果你真的想给 DispatchTime
添加一个整数 msec、μs 或 nsec,你也可以添加一个 DispatchTimeInterval
到 调度时间
.这意味着你可以这样做:
But, if you really want to add an integer number of msec, μs, or nsec to the DispatchTime
, you can also add a DispatchTimeInterval
to a DispatchTime
. That means you can do:
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
类中的 +
运算符的这种单独的重载方法,所有这些都可以无缝地工作.
These all seamlessly work because of this separate overload method for the +
operator in the DispatchTime
class.
public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime
<小时>
有人问如何取消已调度的任务.为此,请使用 DispatchWorkItem
.例如,这会启动一个将在 5 秒内触发的任务,或者如果视图控制器被解除并释放,它的 deinit
将取消任务:
It was asked how one goes about canceling a dispatched task. To do this, use DispatchWorkItem
. For example, this starts a task that will fire in five seconds, or if the view controller is dismissed and deallocated, its deinit
will cancel the task:
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
中[weak self]
捕获列表的使用.这对于避免强引用循环至关重要.另请注意,这不会进行抢占式取消,而只是在任务尚未启动时停止该任务.但是,如果它在遇到 cancel()
调用时已经启动,则该块将完成其执行(除非您手动检查该块内的 isCancelled
).
Note the use of the [weak self]
capture list in the DispatchWorkItem
. This is essential to avoid a strong reference cycle. Also note that this does not do a preemptive cancelation, but rather just stops the task from starting if it hasn’t already. But if it has already started by the time it encounters the cancel()
call, the block will finish its execution (unless you’re manually checking isCancelled
inside the block).
这篇关于如何在 Swift 3、4 和 5 中编写 dispatch_after GCD?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!