Как использовать dispatch_after в Swift 3, 4 и 5 для задержки выполнения кода
Правильный способ задержки выполнения в Swift 3, 4 и 5
Действительно, начиная с Swift 3, Apple изменила API Grand Central Dispatch (GCD). Функция dispatch_after была заменена на метод asyncAfter, который вызывается непосредственно на очереди диспетчеризации (DispatchQueue). Вот как это работает правильно.
Базовый пример для главного потока
Самый распространённый случай — выполнить код на главном потоке через определённое время. Это нужно для обновления UI или отложенных действий.
// Swift 5 — задержка 2 секунды на главном потоке
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Прошло 2 секунды")
// Здесь можно обновлять интерфейс
self.label.text = "Готово!"
}
Обратите внимание: .now() + 2.0 — это время в секундах (Double). Можно использовать любые значения: 0.5, 1.5, 10.0 и т.д.
Задержка на фоновой очереди
Если нужно выполнить тяжёлую работу (например, обработку данных или загрузку файла), используйте глобальную фоновую очередь:
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 3.0) {
// Тяжёлая работа в фоне
let result = self.performHeavyTask()
// Вернуться на главный поток для обновления UI
DispatchQueue.main.async {
self.updateUI(with: result)
}
}
Работа с DispatchTime и DispatchWallTime
Метод asyncAfter принимает параметр deadline типа DispatchTime. Вы можете создать его вручную, если нужно:
let deadline = DispatchTime.now() + .seconds(5)
DispatchQueue.main.asyncAfter(deadline: deadline) {
print("Через 5 секунд")
}
// Или с микросекундами
let preciseDeadline = DispatchTime.now() + .microseconds(500_000) // 0.5 секунды
DispatchQueue.main.asyncAfter(deadline: preciseDeadline) {
print("Через 0.5 секунды")
}
Если вам нужно точное время, не зависящее от изменений системных часов (например, для таймера обратного отсчёта), используйте DispatchWallTime:
let wallDeadline = DispatchWallTime.now() + 2.0
DispatchQueue.global().asyncAfter(wallDeadline: wallDeadline) {
print("Это сработает через 2 секунды по реальному времени")
}
Отмена отложенной задачи
Иногда нужно отменить задачу до её выполнения. Для этого сохраните ссылку на DispatchWorkItem:
// Создаём рабочий элемент
let workItem = DispatchWorkItem {
print("Эта задача может быть отменена")
}
// Запланируем выполнение через 5 секунд
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0, execute: workItem)
// Если нужно отменить (например, пользователь нажал "Отмена")
workItem.cancel()
// Проверка: если задача не была выполнена
if workItem.isCancelled {
print("Задача отменена")
}
Переход со старого синтаксиса
Если вы привыкли к старому dispatch_after, вот таблица соответствия:
- Старый:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), block) - Новый:
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { ... }
Главные преимущества нового API:
- Читаемость — сразу видно очередь и время задержки
- Типобезопасность — компилятор проверяет типы
- Поддержка отмены через DispatchWorkItem
Теперь ваш код будет работать на Swift 3, 4 и 5 без изменений. Удачи!
<<Альтернативный подход: использование Timer
Если вам нужно выполнить действие с задержкой всего один раз, можно использовать Timer.scheduledTimer. Это особенно удобно, когда задержка связана с UI или нужно передать объект как параметр.
Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { timer in
print("Прошло 2 секунды (через Timer)")
// timer будет автоматически invalidated после выполнения
}
Преимущества Timer:
- Простой синтаксис, не требует указания очереди
- Встроенная поддержка повторений (repeats: true)
- Можно легко остановить через
timer.invalidate()
Недостатки по сравнению с asyncAfter:
- Timer работает на RunLoop, поэтому может не сработать в фоновых потоках без явного добавления в RunLoop
- Меньшая точность при высокой нагрузке на систему
- Не подходит для фоновых очередей с QoS
Используйте Timer для простых отложенных действий на главном потоке, а asyncAfter — для более сложных сценариев с фоновыми очередями и точным контролем времени.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги