如何在Swift 3、4和5中编写GCD中的dispatch_after? [英] 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).之所以可以使用将秒数添加为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
添加整数毫秒,μs或nsec,则还可以向DispatchTime
添加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
.例如,这将启动一个任务,该任务将在五秒钟内触发,或者如果视图控制器被解雇并释放,则其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中编写GCD中的dispatch_after?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!