Ich möchte meine App an einem bestimmten Punkt anhalten. Mit anderen Worten, ich möchte, dass meine App den Code ausführt, aber dann an einem bestimmten Punkt 4 Sekunden lang pausiert und dann mit dem Rest des Codes fortfährt. Wie kann ich das machen?
Ich benutze Swift.
Antworten:
Anstelle eines Ruhezustands, der Ihr Programm blockiert, wenn es vom UI-Thread aufgerufen wird, sollten Sie
NSTimer
einen Versand-Timer verwenden.Aber wenn Sie wirklich eine Verzögerung im aktuellen Thread benötigen:
Dies verwendet die
sleep
Funktion von UNIX.quelle
Die Verwendung eines
dispatch_after
Blocks ist in den meisten Fällen besser als die Verwendung,sleep(time)
da der Thread, für den der Schlaf ausgeführt wird, für andere Arbeiten gesperrt ist. Wenn Siedispatch_after
den Thread verwenden, an dem gearbeitet wird, wird er nicht blockiert, sodass er in der Zwischenzeit andere Arbeiten ausführen kann.Wenn Sie am Hauptthread Ihrer Anwendung arbeiten, ist die Verwendung
sleep(time)
für die Benutzererfahrung Ihrer App schlecht, da die Benutzeroberfläche während dieser Zeit nicht reagiert.Versand nach Zeitplan der Ausführung eines Codeblocks, anstatt den Thread einzufrieren:
Swift ≥ 3.0
Swift <3.0
quelle
.now() + .seconds(4)
gibt Fehler:expression type is ambiguous without more context
.now() + .seconds(5)
es ist einfach.now() + 5
Vergleich zwischen verschiedenen Ansätzen in Swift 3.0
1. Schlaf
Diese Methode hat keinen Rückruf. Setzen Sie Codes direkt hinter diese Zeile, um sie in 4 Sekunden auszuführen. Es verhindert, dass Benutzer mit UI-Elementen wie der Testschaltfläche iterieren, bis die Zeit abgelaufen ist. Obwohl die Taste beim Einsetzen des Schlafes eingefroren ist, drehen sich andere Elemente wie die Aktivitätsanzeige immer noch, ohne einzufrieren. Sie können diese Aktion im Ruhezustand nicht erneut auslösen.
2. Dispatch, Perform und Timer
Diese drei Methoden funktionieren ähnlich. Sie werden alle im Hintergrund-Thread mit Rückrufen ausgeführt, nur mit unterschiedlicher Syntax und leicht unterschiedlichen Funktionen.
Der Versand wird häufig verwendet, um etwas im Hintergrund-Thread auszuführen. Es hat den Rückruf als Teil des Funktionsaufrufs
Perform ist eigentlich ein vereinfachter Timer. Es stellt einen Timer mit der Verzögerung ein und löst dann die Funktion per Selektor aus.
Und schließlich bietet der Timer auch die Möglichkeit, den Rückruf zu wiederholen, was in diesem Fall nicht sinnvoll ist
Wenn Sie bei all diesen drei Methoden auf die Schaltfläche klicken, um sie auszulösen, friert die Benutzeroberfläche nicht ein und Sie können erneut darauf klicken. Wenn Sie erneut auf die Schaltfläche klicken, wird ein anderer Timer eingerichtet und der Rückruf wird zweimal ausgelöst.
Abschließend
Keine der vier Methoden funktioniert allein gut genug.
sleep
Deaktiviert die Benutzerinteraktion, sodass der Bildschirm (nicht wirklich) " einfriert " und zu einer schlechten Benutzererfahrung führt. Die anderen drei Methoden frieren den Bildschirm nicht ein, aber Sie können sie mehrmals auslösen. In den meisten Fällen möchten Sie warten, bis Sie den Anruf zurückerhalten, bevor Sie dem Benutzer erlauben, den Anruf erneut zu tätigen.Ein besseres Design wird also eine der drei asynchronen Methoden mit Bildschirmblockierung verwenden. Wenn der Benutzer auf die Schaltfläche klickt, decken Sie den gesamten Bildschirm mit einer durchscheinenden Ansicht ab, auf der sich eine rotierende Aktivitätsanzeige befindet, die dem Benutzer mitteilt, dass das Klicken auf die Schaltfläche ausgeführt wird. Entfernen Sie dann die Ansicht und die Anzeige in der Rückruffunktion, um dem Benutzer mitzuteilen, dass die Aktion ordnungsgemäß ausgeführt wurde usw.
quelle
@objc
vor der Rückruffunktion dieperform(...)
Option hinzufügen müssen . Wie so:@objc func callback() {
Ich stimme Palle zu, dass die Verwendung
dispatch_after
hier eine gute Wahl ist. Aber Sie mögen die GCD-Aufrufe wahrscheinlich nicht, da das Schreiben ziemlich nervig ist . Stattdessen können Sie diesen praktischen Helfer hinzufügen :Jetzt verzögern Sie einfach Ihren Code in einem Hintergrund-Thread wie diesem:
Das Verzögern des Codes im Hauptthread ist noch einfacher:
Wenn Sie ein Framework bevorzugen , das auch einige weitere praktische Funktionen bietet, lesen Sie HandySwift . Sie können es über Karthago oder Accio zu Ihrem Projekt hinzufügen und dann genau wie in den obigen Beispielen verwenden:
quelle
DispatchTime
sie in Swift 2 nicht verfügbar warlet dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
.Sie können dies auch mit Swift 3 tun.
Führen Sie die Funktion nach einer Verzögerung wie folgt aus.
quelle
In Swift 4.2 und Xcode 10.1
Sie haben insgesamt 4 Möglichkeiten zu verzögern. Von diesen Optionen ist es vorzuziehen, nach einiger Zeit eine Funktion aufzurufen oder auszuführen. Der Schlaf () ist mindestens Fall gebräuchlich.
Option 1.
Option 2.
Option 3.
Option 4.
Wenn Sie nach einiger Zeit eine Funktion aufrufen möchten, um etwas auszuführen, verwenden Sie nicht sleep .
quelle
NSTimer
Die Antwort von @nneonneo schlug vor, zu verwenden
NSTimer
, zeigte aber nicht, wie es geht. Dies ist die grundlegende Syntax:Hier ist ein sehr einfaches Projekt, um zu zeigen, wie es verwendet werden kann. Wenn eine Taste gedrückt wird, wird ein Timer gestartet, der nach einer Verzögerung von einer halben Sekunde eine Funktion aufruft.
Die Verwendung
dispatch_time
(wie in Palles Antwort ) ist eine weitere gültige Option. Es ist jedoch schwer abzubrechen . MitNSTimer
, um ein verzögertes Ereignis abzubrechen, bevor es eintritt, müssen Sie nur anrufenDie Verwendung
sleep
wird nicht empfohlen, insbesondere für den Haupt-Thread, da dadurch die gesamte Arbeit am Thread gestoppt wird.Siehe hier für meine ausführlichere Antwort.
quelle
Versuchen Sie die folgende Implementierung in Swift 3.0
Verwendung
quelle
Sie können eine Erweiterung erstellen, um die Verzögerungsfunktion einfach zu verwenden (Syntax: Swift 4.2+).
Verwendung in UIViewController
quelle
Wenn Sie eine Verzögerung von weniger als einer Sekunde einstellen müssen, muss der Parameter .seconds nicht festgelegt werden. Ich hoffe, das ist jemandem nützlich.
quelle
quelle
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {/*Do stuff*/}
ist wahrscheinlich korrekter eWenn Ihr Code bereits in einem Hintergrundthread ausgeführt wird, halten Sie den Thread mit dieser Methode in Foundation an :
Thread.sleep(forTimeInterval:)
Beispielsweise:
(In anderen Antworten finden Sie Vorschläge, wenn Ihr Code im Hauptthread ausgeführt wird.)
quelle
Um eine einfache Zeitverzögerung zu erstellen, können Sie Darwin importieren und dann die Verzögerung mit Sleep (Sekunden) ausführen. Dies dauert jedoch nur ganze Sekunden. Für genauere Messungen können Sie Darwin importieren und usleep (Millionstelsekunden) für sehr genaue Messungen verwenden. Um dies zu testen, schrieb ich:
Welcher druckt, wartet dann 1 Sekunde und druckt, wartet dann 0,4 Sekunden und druckt dann. Alle haben wie erwartet funktioniert.
quelle
das ist das einfachste
quelle