404 Stimmen

Wie erstellt man eine Verzögerung in Swift?

Ich möchte meine App an einem bestimmten Punkt pausieren. Mit anderen Worten, meine App soll den Code ausführen, dann an einem bestimmten Punkt 4 Sekunden lang pausieren und dann mit dem Rest des Codes fortsetzen. Wie kann ich das tun?

Ich benutze Swift.

519voto

Palle Punkte 10536

Die Verwendung eines dispatch_after-Blocks ist in den meisten Fällen besser als die Verwendung von sleep(time), da der Thread, auf dem der Sleep ausgeführt wird, daran gehindert wird, andere Arbeiten zu erledigen. Bei Verwendung von dispatch_after wird der Thread, an dem gearbeitet wird, nicht blockiert, sodass er in der Zwischenzeit andere Arbeiten erledigen kann.
Wenn Sie am Hauptthread Ihrer Anwendung arbeiten, ist die Verwendung von sleep(time) schlecht für die Benutzererfahrung Ihrer App, da die UI während dieser Zeit nicht reagiert.

Dispatch_after plant die Ausführung eines Codeblocks anstelle des Einfrierens des Threads:

Swift 3.0

let seconds = 4.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
    // Fügen Sie hier Ihren Code ein, der mit einer Verzögerung ausgeführt werden soll
}

Swift 5.5 in einem async-Kontext:

func foo() async {
    try await Task.sleep(nanoseconds: UInt64(seconds * Double(NSEC_PER_SEC)))
    // Fügen Sie hier Ihren Code ein, der mit einer Verzögerung ausgeführt werden soll
}

Swift < 3.0

let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
    // Fügen Sie hier Ihren Code ein, der mit einer Verzögerung ausgeführt werden soll
}

375voto

nneonneo Punkte 162093

Statt eines Schlafes, der Ihr Programm blockiert, wenn er vom UI-Thread aus aufgerufen wird, sollten Sie erwägen, NSTimer oder einen Dispatch-Timer zu verwenden.

Aber wenn Sie wirklich eine Verzögerung im aktuellen Thread benötigen:

do {
    sleep(4)
}

Dies verwendet die sleep Funktion von UNIX.

72voto

Fangming Punkte 22809

Vergleich zwischen verschiedenen Ansätzen in Swift 3.0

1. Sleep

Diese Methode hat keinen Rückruf. Setzen Sie den Code direkt nach dieser Zeile ein, um ihn nach 4 Sekunden auszuführen. Es wird den Benutzer daran hindern, mit UI-Elementen wie dem Testbutton zu interagieren, bis die Zeit abgelaufen ist. Obwohl der Button irgendwie "einfriert", wenn der Sleep einsetzt, drehen sich andere Elemente wie der Aktivitätsindikator weiter, ohne einzufrieren. Sie können diese Aktion während des Sleeps nicht erneut auslösen.

sleep(4)
print("fertig") // Hier die Aktionen ausführen

Bildbeschreibung hier eingeben

2. Dispatch, Perform und Timer

Diese drei Methoden funktionieren ähnlich, sie werden alle im Hintergrundthread mit Rückrufen ausgeführt, nur mit unterschiedlicher Syntax und leicht unterschiedlichen Funktionen.

Dispatch wird häufig verwendet, um etwas im Hintergrundthread auszuführen. Der Rückruf ist ein Teil des Funktionsaufrufs.

DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
    print("fertig")
})

Perform ist tatsächlich ein vereinfachter Timer. Er richtet einen Timer mit der Verzögerung ein und löst dann die Funktion durch den Selektor aus.

perform(#selector(callback), with: nil, afterDelay: 4.0)

func callback() {
    print("fertig")
}}

Und schließlich bietet Timer auch die Möglichkeit, den Rückruf zu wiederholen, was in diesem Fall nicht nützlich ist.

Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false)

func callback() {
    print("fertig")
}}

Bei all diesen drei Methoden friert die UI nicht ein, wenn Sie auf den Button klicken, und Sie können erneut darauf klicken. Wenn Sie erneut auf den Button klicken, wird ein weiterer Timer eingerichtet und der Rückruf wird zweimal ausgelöst.

Bildbeschreibung hier eingeben

Zusammenfassend

Keine der vier Methoden funktioniert alleine gut genug. sleep wird die Benutzerinteraktion deaktivieren, sodass der Bildschirm einfriert (nicht wirklich) und ein schlechtes Benutzererlebnis liefert. Die anderen drei Methoden frieren den Bildschirm nicht ein, aber Sie können sie mehrmals auslösen, und die meiste Zeit möchten Sie warten, bis Sie den Rückruf erhalten, bevor Sie dem Benutzer erneut erlauben, den Anruf zu tätigen.

Ein besserer Ansatz wäre die Verwendung einer der drei asynchronen Methoden mit Bildschirmblockierung. Wenn der Benutzer auf den Button klickt, bedecken Sie den gesamten Bildschirm mit einem halbtransparenten View, auf dem ein sich drehender Aktivitätsindikator angezeigt wird, um dem Benutzer mitzuteilen, dass der Buttonklick bearbeitet wird. Entfernen Sie dann das View und den Indikator in der Rückruffunktion, um dem Benutzer mitzuteilen, dass die Aktion ordnungsgemäß behandelt wurde usw.

50voto

Naresh Punkte 14268

In Swift 4.2 und Xcode 10.1

Du hast insgesamt 4 Möglichkeiten zu verzögern. Von diesen ist Option 1 bevorzugt, um eine Funktion nach einiger Zeit aufzurufen oder auszuführen. Der Einsatz von sleep() ist am wenigsten verbreitet.

Option 1.

DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    self.yourFuncHere()
}
//Deine Funktion hier    
func yourFuncHere() {

}

Option 2.

perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)

//Deine Funktion hier  
@objc func yourFuncHere2() {
    print("das ist...")
}

Option 3.

Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)

//Deine Funktion hier  
@objc func yourFuncHere3() {

}

Option 4.

sleep(5)

Wenn du eine Funktion nach einiger Zeit aufrufen möchtest, um etwas auszuführen, verwende nicht sleep.

40voto

Jeehut Punkte 17634

Ich stimme Palle zu, dass es hier eine gute Wahl ist, dispatch_after zu verwenden. Aber du magst die GCD-Aufrufe wahrscheinlich nicht, da sie ziemlich lästig zu schreiben sind. Stattdessen kannst du diesen praktischen Helfer hinzufügen:

public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) {
    let dispatchTime = DispatchTime.now() + seconds
    dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure)
}

public enum DispatchLevel {
    case main, userInteractive, userInitiated, utility, background
    var dispatchQueue: DispatchQueue {
        switch self {
        case .main:                 return DispatchQueue.main
        case .userInteractive:      return DispatchQueue.global(qos: .userInteractive)
        case .userInitiated:        return DispatchQueue.global(qos: .userInitiated)
        case .utility:              return DispatchQueue.global(qos: .utility)
        case .background:           return DispatchQueue.global(qos: .background)
        }
    }
}

Jetzt kannst du ganz einfach deinen Code auf einem Hintergrund-Thread verzögern wie folgt:

delay(bySeconds: 1.5, dispatchLevel: .background) { 
    // verzögerter Code, der auf dem Hintergrund-Thread ausgeführt wird
}

Das Verzögern von Code auf dem Hauptthread ist noch einfacher:

delay(bySeconds: 1.5) { 
    // verzögerter Code, standardmäßig im Hauptthread ausführen
}

Wenn du lieber ein Framework bevorzugst, das noch einige praktische Funktionen bietet, dann schau dir HandySwift an. Du kannst es zu deinem Projekt hinzufügen über SwiftPM und es dann genau wie in den obigen Beispielen verwenden:

import HandySwift    

delay(by: .seconds(1.5)) { 
    // verzögerter Code
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X