Question dispatch_after - GCD dans swift?


J'ai traversé la iBook d'Apple, et n'a trouvé aucune définition de celui-ci:

Quelqu'un peut-il expliquer la structure de dispatch_after?

dispatch_after(<#when: dispatch_time_t#>, <#queue: dispatch_queue_t?#>, <#block: dispatch_block_t?#>)

491
2018-06-04 10:05


origine


Réponses:


Une idée plus claire de la structure:

dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?)

dispatch_time_t est un UInt64. le dispatch_queue_t est en fait un type aliasé à un NSObject, mais vous devez simplement utiliser vos méthodes GCD familières pour obtenir des files d'attente. Le bloc est une fermeture rapide. Plus précisément, dispatch_block_t est défini comme () -> Void, ce qui équivaut à () -> ().

Exemple d'utilisation:

let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
    print("test")
}

MODIFIER:

Je recommande d'utiliser @ matt est vraiment sympa delay fonction.

EDIT 2:

Dans Swift 3, il y aura de nouveaux wrappers pour GCD. Vois ici: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md

L'exemple original serait écrit comme suit dans Swift 3:

let deadlineTime = DispatchTime.now() + .seconds(1)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
    print("test")
}

Notez que vous pouvez écrire le deadlineTime déclaration comme DispatchTime.now() + 1.0 et obtenir le même résultat parce que le + l'opérateur est remplacé comme suit (de même -):

  • func +(time: DispatchTime, seconds: Double) -> DispatchTime
  • func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime

Cela signifie que si vous n'utilisez pas le DispatchTimeInterval  enum et il suffit d'écrire un nombre, il est supposé que vous utilisez des secondes.


671
2018-06-04 10:19



j'utilise dispatch_after si souvent que j'ai écrit une fonction d'utilitaire de niveau supérieur pour simplifier la syntaxe:

func delay(delay:Double, closure:()->()) {
    dispatch_after(
        dispatch_time(
            DISPATCH_TIME_NOW,
            Int64(delay * Double(NSEC_PER_SEC))
        ),
        dispatch_get_main_queue(), closure)
}

Et maintenant vous pouvez parler comme ceci:

delay(0.4) {
    // do stuff
}

Wow, une langue où vous pouvez améliorer la langue. Qu'est-ce qui pourrait être mieux?


Mise à jour pour Swift 3, Xcode 8 Seed 6

Cela semble ne pas valoir la peine, maintenant qu'ils ont amélioré la syntaxe d'appel:

func delay(_ delay:Double, closure:@escaping ()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

1054
2018-06-20 01:57



Pour développer la réponse de Cezary, qui s'exécutera après 1 nanoseconde, je devais faire ce qui suit à exécuter après 4 secondes et demie.

    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: J'ai découvert que mon code d'origine était légèrement faux. Le typage implicite provoque une erreur de compilation si vous ne transtypez pas NSEC_PER_SEC en Double.

Si quelqu'un peut proposer une solution plus optimale, je serais ravi de l'entendre.

== Mise à jour pour Swift 3 ==

C'est super facile et élégant dans Swift 3:

    DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) {
        // ...
    }

91
2018-06-04 20:59



La syntaxe de matt est très agréable et si vous avez besoin d'invalider le bloc, vous pouvez utiliser ceci:

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

Utiliser comme suit

let retVal = delay(2.0) {
    println("Later")
}
delay(1.0) {
    cancel_delay(retVal)
}

crédits

Le lien ci-dessus semble être en panne. Code Objc original de Github


82
2017-08-04 13:55



Apple a un dispatch_after extrait pour Objectif 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#>
});

Voici le même extrait porté sur Rapide 3:

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) {
  <#code to be executed after a specified delay#>
}

20
2017-11-12 00:45



Solution la plus simple dans Swift 3.0 et Swift 4.0

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

Usage

delayWithSeconds(1) {
   //Do something
}

18
2017-10-24 06:00



Une autre façon est d'étendre Double comme ceci:

extension Double {
   var dispatchTime: dispatch_time_t {
       get {
           return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC)))
       }
   }
}

Ensuite, vous pouvez l'utiliser comme ceci:

dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in
            self.dismissViewControllerAnimated(true, completion: nil)
    })

J'aime la fonction de délai de matt, mais juste par préférence, je préfère limiter les fermetures.


14
2017-11-11 05:23



Dans Swift 3.0 

Envoi des files d'attente

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

Envoi après 5 secondes

    DispatchQueue.main.after(when: DispatchTime.now() + 5) {
        print("Dispatch after 5 sec")
    }

8
2017-07-14 05:33