Как мне написать dispatch_after GCD в Swift 3, 4 и 5?
В 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?
Ответы
Ответ 1
Синтаксис просто:
// 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
, вы также можете добавить DispatchTimeInterval
к DispatchTime
. Это означает, что вы можете сделать:
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
. Например, это запускает задачу, которая будет запущена через пять секунд, или, если контроллер представления уволен и освобожден, его 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() { ... }
}
Обратите внимание на использование списка захвата [weak self]
в DispatchWorkItem
. Это важно, чтобы избежать сильного референтного цикла. Также обратите внимание, что это не делает упреждающего отмены, а просто останавливает запуск задачи, если это еще не сделано. Но если он уже запустился к тому времени, когда встретился с вызовом cancel()
, блок завершит свое выполнение (если только вы вручную не проверяете isCancelled
внутри блока).
Ответ 2
Swift 4:
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
// Code
}
В течение времени .seconds(Int)
также могут использоваться .microseconds(Int)
и .nanoseconds(Int)
.
Ответ 3
Если вы просто хотите, чтобы функция задержки в
Свифт 4 и 5
func delay(interval: TimeInterval, closure: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
closure()
}
}
Вы можете использовать его как:
delay(interval: 1) {
print("Hi!")
}
Ответ 4
после выпуска Swift 3, также необходимо добавить @escaping
func delay(_ delay: Double, closure: @escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
closure()
}
}
Ответ 5
Swift 4
Вы можете создать расширение в DispatchQueue и добавить функцию delay, которая использует функцию DispatchQueue
asyncAfter для внутреннего использования.
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")
}
Ответ 6
Несколько иной аромат принятого ответа.
Swift 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)")
}
Ответ 7
вызов DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)
Я настоятельно рекомендую использовать инструменты Xcode для преобразования в Swift 3 (Edit > Convert > To Current Swift Syntax). Это поймало это для меня.
Ответ 8
В Swift 4.1 и Xcode 9.4.1
Простой ответ...
//To call function after 5 seconds time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
//Here call your function
}
Ответ 9
Ни в одном из ответов не упоминается работа в неосновной теме, поэтому добавляю свои 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) {
// ...
}
Ответ 10
Swift 5 и выше
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
// code to execute
})
Ответ 11
Это работало для меня в Swift 3
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
Ответ 12
Вы можете использовать
DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(100)) {
// Code
}
Ответ 13
попробуйте это
let when = DispatchTime.now() + 1.5
DispatchQueue.main.asyncAfter(deadline: when) {
//some code
}