it-swarm.com.de

dispatch_after - GCD in Swift?

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?#>)
518
Kumar KL

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 DispatchTimeIntervalenum verwenden und nur eine Zahl eingeben, wird davon ausgegangen, dass Sie Sekunden verwenden.

722
Cezary Wojcik

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?


Update für Swift 3, Xcode 8 Seed 6

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

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) {
    // ...
}
100
brindy

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

Credits

Link oben scheint down zu sein. Ursprünglicher Objc-Code von Github

83
Waam

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#>
}
20
Senseful

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
}
20
Vakas

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.

14
garafajon

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

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
}

}

4
A.G

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 .

Eine Aufgabe mit NSTimer verzögern

Erstellen 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."
}

Anmerkungen

  • Wenn Sie die Aktion abbrechen müssen, bevor sie ausgeführt wird, rufen Sie einfach timer.invalidate() auf.
  • Für eine wiederholte Aktion verwenden Sie 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 .

3
Suragch

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

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")
}
2
Suhit Patil

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())
}
1
Sanjay Mali

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
}
1
Hardeep Singh

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
}
1
Dschee

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);
});
1
Ankit garg
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

1
CrazyPro007

Swift 4 hat einen ziemlich kurzen Weg, dies zu tun:

Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in
    // Your stuff here
    print("hello")
}
0
Vlady Veselinov

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()))
}
0
Maxim Makhun

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")
}
0
Steven

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

In Swift 4

Verwenden Sie dieses Snippet:

    let delayInSec = 1.0
    DispatchQueue.main.asyncAfter(deadline: .now() + delayInSec) {
       // code here
       print("It works")
    }
0
BlackRock