Avatar ·

Как запрограммировать задержку (delay) в Swift 3?

Всем привет! Я только начал изучать Swift 3 и никак не могу разобраться с созданием задержки в коде. Мне нужно, чтобы после нажатия на кнопку, через 2 секунды выполнилось какое-то действие (например, скрыть UILabel). Раньше я видел, что в Swift 2 использовался `dispatch_after`, но в Swift 3 этот синтаксис, кажется, изменился. Я пробовал написать вот так: ```swift dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) { // мой код } ``` Но Xcode выдаёт ошибку: `'dispatch_after' is unavailable: Use DispatchQueue.main.asyncAfter`. Я понимаю, что нужно использовать что-то другое, но документация для новичка кажется сложной. Подскажите, пожалуйста, как правильно сделать задержку в Swift 3? Желательно с простым примером, чтобы я мог сразу вставить в свой проект. Заранее спасибо! <<>>

Правильный способ: DispatchQueue.asyncAfter

В Swift 3 и последующих версиях Apple полностью переработала API Grand Central Dispatch (GCD). Старый C-подобный синтаксис dispatch_after заменён на более читаемый и безопасный метод DispatchQueue.asyncAfter. Вот как это работает:

Базовый пример задержки в 2 секунды

// Выполнить код на главном потоке через 2 секунды
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
    // Ваш код здесь
    print("Прошло 2 секунды!")
    myLabel.isHidden = true
}

Разберём по частям:

  • DispatchQueue.main — указывает, что код будет выполняться на главном потоке (UI-потоке). Это важно, если вы обновляете интерфейс (UILabel, UIButton и т.д.).
  • .asyncAfter — метод, который планирует выполнение блока кода через указанное время.
  • deadline: .now() + 2.0 — время, через которое код должен выполниться. .now() — это текущий момент, а + 2.0 — добавляет 2 секунды.

Как сделать задержку на фоновом потоке?

Если вам не нужно обновлять UI, а нужно выполнить тяжёлую работу (например, загрузку данных), используйте глобальную очередь:

DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 3.0) {
    // Фоновая задача через 3 секунды
    print("Это выполнится на фоновом потоке")
}

Более точная задержка с микросекундами

Если вам нужно указать время с высокой точностью, используйте DispatchTimeInterval:

let delayInSeconds = 1.5
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(Int(delayInSeconds))) {
    // Через 1.5 секунды
}

// Или напрямую с миллисекундами:
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(1500)) {
    // Тот же эффект
}

Отмена запланированной задержки

Иногда нужно отменить задержку до её выполнения (например, если пользователь нажал кнопку повторно). Для этого сохраните DispatchWorkItem:

// Создаём задачу
let workItem = DispatchWorkItem {
    print("Эта задача будет выполнена через 5 секунд, если не отменена")
}

// Планируем
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0, execute: workItem)

// Отменяем (если нужно)
workItem.cancel()

Почему старый код не работает?

В Swift 3 Apple убрала все C-функции GCD. Вместо dispatch_after теперь используется объектно-ориентированный подход через DispatchQueue. Это делает код более безопасным и читаемым. Всегда используйте DispatchQueue.main.asyncAfter для UI-операций и DispatchQueue.global().asyncAfter для фоновых задач.

Теперь вы можете смело вставлять этот код в свой проект. Удачи!

<<>>

Альтернативный подход: Timer (NSTimer)

Если вам нужно выполнить действие только один раз с задержкой, можно использовать Timer. Этот метод особенно удобен, когда задержка связана с повторяющимися событиями или есть вероятность отмены:

Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { timer in
    // Код выполнится через 2 секунды
    self.myLabel.isHidden = true
}

Преимущества Timer:

  • Легко отменить: сохраните ссылку на таймер и вызовите timer.invalidate().
  • Поддерживает повторение (repeats: true), что полезно для периодических задач.
  • Не требует указания очереди — по умолчанию выполняется на главном потоке.

Недостаток: таймер чувствителен к циклу выполнения (RunLoop). Если главный поток занят, задержка может увеличиться. Для точных задержек лучше использовать asyncAfter.

Пример с отменой:

var myTimer: Timer?

func startDelay() {
    myTimer = Timer.scheduledTimer(withTimeInterval: 2.0, repeats: false) { _ in
        print("Выполнено")
    }
}

func cancelDelay() {
    myTimer?.invalidate()
    myTimer = nil
}

Выбирайте asyncAfter для простых одноразовых задержек и Timer — когда нужна гибкость управления.