Jak zaprogramować opóźnienie w Swift 3

330

We wcześniejszych wersjach Swift można było utworzyć opóźnienie za pomocą następującego kodu:

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
}

Ale teraz, w Swift 3, Xcode automatycznie zmienia 6 różnych rzeczy, ale pojawia się następujący błąd: „Nie można przekonwertować DispatchTime.nowna wartość oczekiwaną dispatch_time_taka UInt64”.

Jak stworzyć opóźnienie przed uruchomieniem sekwencji kodu w Swift 3?

owlswipe
źródło

Odpowiedzi:

965

Po wielu badaniach w końcu doszedłem do wniosku.

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

Tworzy to pożądany efekt „oczekiwania” w Swift 3 i Swift 4.

Zainspirowany częścią tej odpowiedzi .

owlswipe
źródło
7
Przydatny wkład, dzięki! Aktualizacja do najnowszego Swift 3:DispatchQueue.main.asyncAfter(deadline: when)
Rogare,
77
Możesz sprawić, by Twój kod był nieco szybszy, zastępując „+ 2” przez „+ .seconds (2)”. Lub, dla maksymalnej swiftyness, możesz upuścić pierwszą linię i zastąpić „termin: kiedy” terminem: .now () + .seconds (2) ”.
RenniePet
2
@ OctavioAntonioCedeño Z przyjemnością pomoże. Naprawdę mnie to
martwiło
5
Nadal działa 3/12/2017. Bardzo za to dziękuję :)
John Leonardo
3
Dosłownie mój najczęściej odwiedzany post na SO. Łatwiej jest znaleźć ten post niż go zapamiętać lub znaleźć gdzie indziej w moim kodzie;)
barrylachapelle
154

Lubię notację jednowierszową dla GCD, jest bardziej elegancka:

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

Ponadto w iOS 10 mamy nowe metody Timera, np. Inicjalizator bloku:

(więc opóźnione działanie może zostać anulowane)

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

Przy okazji, pamiętaj: domyślnie zegar jest dodawany do domyślnego trybu pętli uruchamiania. Oznacza to, że stoper może zostać zawieszony, gdy użytkownik wchodzi w interakcję z interfejsem użytkownika aplikacji (na przykład podczas przewijania UIScrollView). Możesz rozwiązać ten problem, dodając stoper do określonego trybu pętli uruchamiania:

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

W tym poście na blogu znajdziesz więcej szczegółów.

Victor Do
źródło
4
Dobry chwyt! Jeszcze tego nie widziałem.
julien_c
8
plus jeden za porównanie Timera i zrzeczenie się odpowiedzialności za główny runloop!
Martin
2
Dobry chwyt! To jest inżynieria.
Onur Şahindur
56

Wypróbuj następującą funkcję zaimplementowaną w Swift 3.0 i nowszych wersjach

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

Stosowanie

delayWithSeconds(1) {
   //Do something
}
Vakas
źródło
5
Zasadniczo właśnie skopiowałeś tę odpowiedź, ale tak, to dobrze, dzięki.
owlswipe
2
Jak to anulować?
Sourav Chandra,
24

Wypróbuj poniższy kod dla opóźnienia

//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
}
Anand Verma
źródło
1
Pierwszy sposób wyświetla błąd „Użycie nierozpoznanego identyfikatora„ opóźnienie ””
Jerry Chong,
5
Ten programista pracuje z metodą pomocniczą w swojej bazie kodu i już od dłuższego czasu. Opóźnienie było więc kodem, którego używał przez pewien czas, nie wiedząc, że nie jest to oddzielny zestaw SDK firmy Apple.
Nick Perkins
4

Jednym ze sposobów jest użycie DispatchQueue.main.asyncAfter ponieważ wiele osób odpowiedziało.

Innym sposobem jest użycie perform(_:with:afterDelay:). Więcej informacji tutaj

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

@IBAction func delayedFunc() {
    // implement code
}
Zohaib Brohi
źródło
1

// Uruchamia funkcję po x sekundach

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

//Posługiwać się:-

runThisAfterDelay(seconds: x){
  //write your code here
}
Pratyush Pratik
źródło