Ich habe das iBook von Apple durchgesehen und konnte keine Definition davon finden:
Kann jemand die Struktur von dispatch_after
erklären?
dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)
Eine klarere Vorstellung von der Struktur:
dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)
dispatch_time_t
Ist ein UInt64
. Das dispatch_queue_t
Ist eigentlich ein Alias mit einem NSObject
, aber Sie sollten nur Ihre bekannten GCD-Methoden verwenden, um Warteschlangen zu erhalten. Der Block ist ein Swift Closure. Insbesondere ist dispatch_block_t
Als () -> Void
Definiert, was () -> ()
Entspricht.
Anwendungsbeispiel:
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
print("test")
}
EDIT:
Ich empfehle die Verwendung von @matt's wirklich nette delay
Funktion .
EDIT 2:
In Swift 3 wird es neue Wrapper für GCD geben. Siehe hier: https://github.com/Apple/Swift-evolution/blob/master/proposals/0088- libdispatch-for-Swift3.md
Das ursprüngliche Beispiel würde in Swift 3 wie folgt geschrieben:
let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
print("test")
}
Beachten Sie, dass Sie die deadlineTime
-Deklaration als DispatchTime.now() + 1.0
schreiben können und dass Sie dasselbe Ergebnis erhalten, da der Operator +
Wie folgt überschrieben wird (ähnlich für -
):
func +(time: DispatchTime, seconds: Double) -> DispatchTime
func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime
Das heißt, wenn Sie nicht DispatchTimeInterval
enum
verwenden und nur eine Zahl eingeben, wird davon ausgegangen, dass Sie Sekunden verwenden.
Ich benutze dispatch_after
so oft, dass ich eine Dienstprogrammfunktion auf oberster Ebene geschrieben habe, um die Syntax zu vereinfachen:
func delay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
Und jetzt kannst du so reden:
delay(0.4) {
// do stuff
}
Wow, eine Sprache, in der Sie die Sprache verbessern können. Was wäre besser?
Scheint fast nicht mehr wert zu sein, nachdem sie die Aufrufsyntax verbessert haben:
func delay(_ delay:Double, closure:@escaping ()->()) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
Um auf Cezarys Antwort einzugehen, die nach 1 Nanosekunde ausgeführt wird, musste ich nach 4 1/2 Sekunden die folgenden Schritte ausführen.
let delay = 4.5 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue(), block)
Edit: Ich entdeckte, dass mein ursprünglicher Code etwas falsch war. Die implizite Typisierung verursacht einen Kompilierungsfehler, wenn Sie NSEC_PER_SEC nicht in ein Double konvertieren.
Wenn jemand eine optimalere Lösung vorschlagen kann, würde ich mich sehr freuen.
== Update für Swift 3 ==
Das ist in Swift 3 super einfach und elegant:
DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
// ...
}
Mats Syntax ist sehr nett und wenn Sie den Block ungültig machen müssen, möchten Sie vielleicht Folgendes verwenden:
typealias dispatch_cancelable_closure = (cancel : Bool) -> Void
func delay(time:NSTimeInterval, closure:()->Void) -> dispatch_cancelable_closure? {
func dispatch_later(clsr:()->Void) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(time * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), clsr)
}
var closure:dispatch_block_t? = closure
var cancelableClosure:dispatch_cancelable_closure?
let delayedClosure:dispatch_cancelable_closure = { cancel in
if closure != nil {
if (cancel == false) {
dispatch_async(dispatch_get_main_queue(), closure!);
}
}
closure = nil
cancelableClosure = nil
}
cancelableClosure = delayedClosure
dispatch_later {
if let delayedClosure = cancelableClosure {
delayedClosure(cancel: false)
}
}
return cancelableClosure;
}
func cancel_delay(closure:dispatch_cancelable_closure?) {
if closure != nil {
closure!(cancel: true)
}
}
Verwenden Sie wie folgt
let retVal = delay(2.0) {
println("Later")
}
delay(1.0) {
cancel_delay(retVal)
}
Link oben scheint down zu sein. Ursprünglicher Objc-Code von Github
Apple hat ein dispatch_after-Snippet für Objective-C :
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
<#code to be executed after a specified delay#>
});
Hier ist derselbe Ausschnitt nach Swift 3 portiert:
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) {
<#code to be executed after a specified delay#>
}
Einfachste Lösung in Swift 3.0 und Swift 4.0
func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
completion()
}
}
Verwendungszweck
delayWithSeconds(1) {
//Do something
}
Eine andere Möglichkeit ist, Double so zu erweitern:
extension Double {
var dispatchTime: dispatch_time_t {
get {
return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC)))
}
}
}
Dann kannst du es so benutzen:
dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
})
Ich mag die Verzögerungsfunktion von Matt, aber nur aus Vorliebe möchte ich die Passverschlüsse einschränken.
In Swift 3.0
Versandwarteschlangen
DispatchQueue(label: "test").async {
//long running Background Task
for obj in 0...1000 {
print("async \(obj)")
}
// UI update in main queue
DispatchQueue.main.async(execute: {
print("UI update on main queue")
})
}
DispatchQueue(label: "m").sync {
//long running Background Task
for obj in 0...1000 {
print("sync \(obj)")
}
// UI update in main queue
DispatchQueue.main.sync(execute: {
print("UI update on main queue")
})
}
Versand nach 5 Sekunden
DispatchQueue.main.after(when: DispatchTime.now() + 5) {
print("Dispatch after 5 sec")
}
Swift 3.0 Version
Im Anschluss an die Schließungsfunktion führen Sie einige Aufgaben nach einer Verzögerung im Haupt-Thread aus.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Rufen Sie diese Funktion wie folgt auf:
performAfterDelay(delay: 4.0) {
print("test")
}
1) Fügen Sie diese Methode als Teil der UIViewController-Erweiterung hinzu.
extension UIViewController{
func runAfterDelay(delay: NSTimeInterval, block: dispatch_block_t) {
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
dispatch_after(time, dispatch_get_main_queue(), block)
}
}
Rufen Sie diese Methode bei VC auf:
self.runAfterDelay(5.0, block: {
//Add code to this block
print("run After Delay Success")
})
2) performSelector ("yourMethod Name", withObject: nil, afterDelay: 1)
3)
override func viewWillAppear(animated: Bool) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in
//Code Here
})
// kompaktes Formular
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
//Code here
}
}
Obwohl es sich nicht um die ursprüngliche Frage des OP handelt, wurden bestimmte NSTimer
-bezogene Fragen als Duplikate dieser Frage markiert, daher ist es sinnvoll, hier eine NSTimer
-Antwort hinzuzufügen.
NSTimer
vs dispatch_after
NSTimer
ist ein höherer Pegel, während dispatch_after
ein niedrigerer Pegel ist.NSTimer
ist einfacher abzubrechen. Das Abbrechen von dispatch_after
erfordert das Schreiben von mehr Code .NSTimer
verzögernErstellen Sie eine NSTimer
-Instanz.
var timer = NSTimer()
Starten Sie den Timer mit der Verzögerung, die Sie benötigen.
// invalidate the timer if there is any chance that it could have been called before
timer.invalidate()
// delay of 2 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Fügen Sie eine Funktion hinzu, die nach der Verzögerung aufgerufen werden soll (wobei Sie den Namen verwenden, den Sie oben für den Parameter selector
verwendet haben).
func delayedAction() {
print("Delayed action has now started."
}
timer.invalidate()
auf.repeats: true
. Wenn Sie ein einmaliges Ereignis haben, ohne abzubrechen, müssen Sie die Instanzvariable timer
nicht erstellen. Folgendes wird ausreichen:
NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)
Siehe meine ausführlichere Antwort hier .
Verwenden Sie diese Funktion für mehrere Funktionen. Dies ist sehr hilfreich, wenn Sie Animationen oder Activity Loader für statische Funktionen oder jedes UI-Update verwenden.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
// Call your function 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
// Call your function 2
}
}
Zum Beispiel - Verwenden Sie eine Animation, bevor eine tableView neu geladen wird. Oder eine andere Aktualisierung der Benutzeroberfläche nach der Animation.
*// Start your amination*
self.startAnimation()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
*// The animation will execute depending on the delay time*
self.stopAnimation()
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
*// Now update your view*
self.fetchData()
self.updateUI()
}
}
Swift 3 & 4:
Sie können eine Erweiterung in DispatchQueue erstellen und eine Funktionsverzögerung hinzufügen, die intern die DispatchQueue-Funktion asyncAfter verwendet
extension DispatchQueue {
static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
let timeInterval = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure)
}
}
benutzen:
DispatchQueue.delay(.seconds(1)) {
print("This is after delay")
}
Verzögern des GCD-Anrufs mit asyncAfter in Swift
let delayQueue = DispatchQueue(label: "com.theappmaker.in", qos: .userInitiated)
let additionalTime: DispatchTimeInterval = .seconds(2)
Wir können verzögern als ** Mikrosekunden , Millisekunden , Nanosekunden
delayQueue.asyncAfter(deadline: .now() + 0.60) {
print(Date())
}
delayQueue.asyncAfter(deadline: .now() + additionalTime) {
print(Date())
}
Ich bevorzuge immer Erweiterungen anstelle von freien Funktionen.
Swift 4
public extension DispatchQueue {
private class func delay(delay: TimeInterval, closure: @escaping () -> Void) {
let when = DispatchTime.now() + delay
DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}
class func performAction(after seconds: TimeInterval, callBack: @escaping (() -> Void) ) {
DispatchQueue.delay(delay: seconds) {
callBack()
}
}
}
Verwenden Sie wie folgt.
DispatchQueue.performAction(after: 0.3) {
// Code Here
}
Ein weiterer Helfer, der Ihren Code verzögert, ist 100% Swift in use und erlaubt optional Auswahl eines anderen Threads, um Ihren verzögerten Code auszuführen:
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 einfach verzögern Sie Ihren Code im Main-Thread wie folgt:
delay(bySeconds: 1.5) {
// delayed code
}
Wenn Sie Ihren Code auf einen anderen Thread verschieben möchten:
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
Wenn Sie ein Framework bevorzugen, das auch mehr nützliche Funktionen bietet, checken Sie HandySwift aus. Sie können es zu Ihrem Projekt hinzufügen über Carthage und dann genau wie in den obigen Beispielen verwenden, z.
import HandySwift
delay(bySeconds: 1.5) {
// delayed code
}
Das hat bei mir funktioniert.
Swift 3:
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: \(time1 + time2)")
}
Ziel c:
CGFloat time1 = 3.49;
CGFloat time2 = 8.13;
// Delay 2 seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
CGFloat newTime = time1 + time2;
NSLog(@"New time: %f", newTime);
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// ...
});
Die Funktion dispatch_after(_:_:_:)
benötigt drei Parameter:
eine Verzögerung
eine Versandwarteschlange
ein Block oder ein Verschluss
Die Funktion dispatch_after(_:_:_:)
ruft den Block oder die Schließung der Dispatch-Warteschlange auf, die nach einer bestimmten Verzögerung an die Funktion übergeben wird. Beachten Sie, dass die Verzögerung mit der Funktion dispatch_time(_:_:)
erstellt wird. Denken Sie daran, weil wir diese Funktion auch in Swift verwenden.
Ich empfehle, das Tutorial durchzugehen Raywenderlich Dispatch Tutorial
Swift 4 hat einen ziemlich kurzen Weg, dies zu tun:
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
// Your stuff here
print("hello")
}
Hier ist die synchrone Version von asyncAfter in Swift:
let deadline = DispatchTime.now() + .seconds(3)
let semaphore = DispatchSemaphore.init(value: 0)
DispatchQueue.global().asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
semaphore.signal()
}
semaphore.wait()
Zusammen mit asynchronen:
let deadline = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadline) {
dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
}
Jetzt mehr als syntaktischer Zucker für asynchrone Sendungen in Grand Central Dispatch (GCD) in Swift.
poddatei hinzufügen
pod 'AsyncSwift'
Dann können Sie es so verwenden.
let seconds = 3.0
Async.main(after: seconds) {
print("Is called after 3 seconds")
}.background(after: 6.0) {
print("At least 3.0 seconds after previous block, and 6.0 after Async code is called")
}
verwenden Sie diesen Code, um einige auf die Benutzeroberfläche bezogene Aufgaben nach 2,0 Sekunden auszuführen.
let delay = 2.0
let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
let mainQueue = dispatch_get_main_queue()
dispatch_after(delayInNanoSeconds, mainQueue, {
print("Some UI related task after delay")
})
Swift 3.0 Version
Im Anschluss an die Schließungsfunktion führen Sie einige Aufgaben nach einer Verzögerung im Haupt-Thread aus.
func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
onCompletion()
})
}
Rufen Sie diese Funktion wie folgt auf:
performAfterDelay(delay: 4.0) {
print("test")
}
In Swift 4
Verwenden Sie dieses Snippet:
let delayInSec = 1.0
DispatchQueue.main.asyncAfter(deadline: .now() + delayInSec) {
// code here
print("It works")
}