Как сделать задержку (delay) в Swift 3? Использую DispatchQueue, но код не работает
Правильный способ сделать задержку в Swift 3
Проблема в вашем коде — это неверное использование типа DispatchTime. В Swift 3 нужно явно указывать, что вы добавляете секунды к текущему времени с помощью DispatchTimeInterval или числа с плавающей точкой.
Вот корректный синтаксис:
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Прошло 2 секунды")
}
Этот код работает в Swift 3, если вы импортировали Foundation или UIKit. Ошибка у вас возникала, скорее всего, из-за того, что вы пробовали писать DispatchTime.now() + 2.0 — это неверно, потому что DispatchTime.now() возвращает объект DispatchTime, а не статическое свойство.
Почему это работает?
.now()— это статический метод, который возвращает текущее время в форматеDispatchTime.+ 2.0— Swift автоматически интерпретируетDoubleкакDispatchTimeInterval(в секундах) и создаёт новое время.asyncAfter(deadline:)— выполняет блок после указанного времени.
Примеры для разных потоков
1. Задержка на главном потоке (обновление UI):
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.label.text = "Привет через 3 секунды"
}
2. Задержка на фоновом потоке (тяжёлые вычисления):
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 1.5) {
// Выполняем загрузку данных
let data = fetchDataFromNetwork()
DispatchQueue.main.async {
// Возвращаемся на главный поток для UI
self.updateUI(with: data)
}
}
3. С явным указанием DispatchTimeInterval:
let delay = DispatchTimeInterval.seconds(5)
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
print("Прошло 5 секунд")
}
Распространённые ошибки и их решения
- Ошибка:
Binary operator '+' cannot be applied to operands of type 'DispatchTime' and 'Double'
Решение: Используйте.now() + 2.0(статический метод), а неDispatchTime.now(). - Ошибка: Код выполняется сразу, без задержки
Решение: Проверьте, что вы не забыли указатьasyncAfterвместоasync. - Ошибка: Задержка больше или меньше ожидаемой
Решение: ИспользуйтеDispatchTimeInterval.milliseconds(500)для точных миллисекунд.
Что делать, если нужно отменить задержку?
Для отмены используйте DispatchWorkItem:
let workItem = DispatchWorkItem {
print("Этот блок можно отменить")
}
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0, execute: workItem)
// Если передумали:
workItem.cancel()
Теперь ваш код будет работать корректно. Помните: в Swift 3 синтаксис стал чище и безопаснее, но требует внимания к типам. Удачи!
<<Альтернативный подход: использование Perform с задержкой
Если вам не хочется работать с DispatchQueue, можно использовать старый добрый perform(_:with:afterDelay:) из Objective-C. Этот метод доступен для любых классов, наследующих NSObject (включая UIViewController):
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
perform(#selector(delayedAction), with: nil, afterDelay: 2.0)
}
@objc func delayedAction() {
print("Это выполнится через 2 секунды")
}
}
Плюсы:
- Простой синтаксис, знакомый разработчикам с опытом Objective-C.
- Можно отменить с помощью
NSObject.cancelPreviousPerformRequests(withTarget:selector:object:).
Минусы:
- Требует объявления метода с атрибутом
@objc. - Работает только на главном потоке (если не указано иное).
- Менее гибкий, чем
DispatchQueue(нельзя легко переключить QoS или очередь).
Этот способ подходит для простых случаев, когда задержка нужна на главном потоке и вы не хотите углубляться в Grand Central Dispatch. Однако для продакшена рекомендую использовать asyncAfter — это современный и надёжный подход.
Ответов пока нет.
Войдите чтобы оставить ответ