Як запрограмувати затримку в Swift 3


330

У попередніх версіях Swift можна створити затримку із наступним кодом:

let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
    //put your code which should be executed with a delay here
}

Але тепер, у Swift 3, Xcode автоматично змінює 6 різних речей, але тоді з'являється така помилка: "Неможливо перетворити DispatchTime.nowна очікувану величину dispatch_time_tака UInt64".

Як можна створити затримку перед запуском послідовності коду в Swift 3?

Відповіді:


966

Після багатьох досліджень я нарешті з’ясував це.

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { // Change `2.0` to the desired number of seconds.
   // Code you want to be delayed
}

Це створює бажаний ефект "очікування" у Swift 3 та Swift 4.

Натхненна частиною цієї відповіді .


7
Корисний внесок, дякую! Оновлення для останнього Swift 3:DispatchQueue.main.asyncAfter(deadline: when)
Rogare

77
Ви можете зробити свій код трохи швидким, замінивши "+ 2" на "+ .seconds (2)". Або для остаточної швидкості ви можете скинути перший рядок і замінити "крайній термін: коли" на "крайній термін: .now () + .секунди (2)".
RenniePet

2
@ OctavioAntonioCedeño Раді допомогти. Це насправді
надовго набридло на

5
Ще працює 3.12.2017. Дякую вам за це :)
Джон Леонардо

3
Буквально мій самий відвідуваний пост на SO. Простіше знайти цю публікацію, ніж насправді запам'ятати її або знайти її в іншому місці мого коду;)
barrylachapelle

154

Мені подобається однорядне позначення для GCD, воно більш елегантне:

    DispatchQueue.main.asyncAfter(deadline: .now() + 42.0) {
        // do stuff 42 seconds later
    }

Також в iOS 10 у нас є нові таймерні методи, наприклад ініціалізатор блоків:

(тому затримка дії може бути скасована)

    let timer = Timer.scheduledTimer(withTimeInterval: 42.0, repeats: false) { (timer) in
        // do stuff 42 seconds later
    }

Btw, майте на увазі: за замовчуванням в режим циклу запуску за замовчуванням додається таймер. Це означає, що таймер може бути заморожено, коли користувач взаємодіє з інтерфейсом вашого додатка (наприклад, при прокрутці UIScrollView). Ви можете вирішити цю проблему, додавши таймер до певного режиму циклу запуску:

RunLoop.current.add(timer, forMode: .common)

У цій публікації в блозі ви можете дізнатися більше деталей.


4
Гарний улов! Я цього ще не бачив.
julien_c

8
плюс один для порівняння Таймера та відмови від відповідальності про основний цикл запуску!
Мартін

2
Приємний улов! Це інженерія.
Onur Şahindur

56

Спробуйте виконати наступну функцію, реалізовану в Swift 3.0 і вище

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

Використання

delayWithSeconds(1) {
   //Do something
}

5
Ви в основному просто скопіювали цю відповідь, але так, це добре, дякую.
Owlswipe

2
Як це скасувати?
Сурав Чандра

24

Спробуйте наведений нижче код для затримки

//MARK: First Way

func delayForWork() {
    delay(3.0) {
        print("delay for 3.0 second")
    }
}

delayForWork()

// MARK: Second Way

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    // your code here delayed by 0.5 seconds
}

1
Перший спосіб відображає помилку "Використання невирішеного ідентифікатора" затримка ""
Джеррі Чонг

5
Цей програміст працює з помічницьким методом у своїй кодовій базі і працює вже давно. Тож затримка була кодом, який він деякий час використовував, не знаючи, що це не крім SDK Apple.
Нік Перкінс

4

Один із способів - це використовувати так, DispatchQueue.main.asyncAfterяк відповіли багато людей.

Інший спосіб - використання perform(_:with:afterDelay:). Детальніше тут

perform(#selector(delayedFunc), with: nil, afterDelay: 3)

@IBAction func delayedFunc() {
    // implement code
}

1

// Працює через x секунд

public static func runThisAfterDelay(seconds: Double, after: @escaping () -> Void) {
    runThisAfterDelay(seconds: seconds, queue: DispatchQueue.main, after: after)
}

public static func runThisAfterDelay(seconds: Double, queue: DispatchQueue, after: @escaping () -> Void) {
    let time = DispatchTime.now() + Double(Int64(seconds * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
    queue.asyncAfter(deadline: time, execute: after)
}

// Використання: -

runThisAfterDelay(seconds: x){
  //write your code here
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.