В Swift 2 я мог использовать dispatch_after, чтобы отложить действие с помощью 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?

Ответы (12)

Синтаксис просто:

// to run something in 0.1 seconds

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

Обратите внимание: приведенный выше синтаксис добавления секунд как Double кажется источником путаницы (особенно, поскольку мы привыкли добавлять nsec). Этот синтаксис «добавить секунды как Double» работает, потому что крайний срок - это 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 внутри блока).

Вы можете использовать

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

Несколько иной вариант принятого ответа.

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)")
 }

В 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
}

Swift 4:

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

Для времени .seconds (Int), .microseconds (Int) и .nanoseconds (Int) также могут использоваться.

Swift 5 и выше

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

после выпуска Swift 3, также необходимо добавить @escaping

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

попробуйте это

let when = DispatchTime.now() + 1.5
    DispatchQueue.main.asyncAfter(deadline: when) {
        //some code
    }

Если вам просто нужна функция задержки в

Swift 4 и 5

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

Вы можете использовать это как:

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

Swift 4

Вы можете создать расширение для DispatchQueue и добавить функцию задержки, которая использует внутреннюю функцию 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")
}

вызов DispatchQueue.main.after (когда: DispatchTime, выполнить: () -> Void)

Я настоятельно рекомендую использовать инструменты Xcode для преобразования в Swift 3 (Edit> Convert> To Current Swift Syntax). У меня это поймало

Ни в одном из ответов не упоминалось, что он работает в неосновном потоке, поэтому добавляю мои 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) {
    // ...
}

2022 WebDevInsider