dispatch_after - GCD in Swift? dispatch_after - GCD in Swift? objective-c objective-c

dispatch_after - GCD in Swift?


I use dispatch_after so often that I wrote a top-level utility function to make the syntax simpler:

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

And now you can talk like this:

delay(0.4) {    // do stuff}

Wow, a language where you can improve the language. What could be better?


Update for Swift 3, Xcode 8 Seed 6

Seems almost not worth bothering with, now that they've improved the calling syntax:

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


A clearer idea of the structure:

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

dispatch_time_t is a UInt64. The dispatch_queue_t is actually type aliased to an NSObject, but you should just use your familiar GCD methods to get queues. The block is a Swift closure. Specifically, dispatch_block_t is defined as () -> Void, which is equivalent to () -> ().

Example usage:

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

EDIT:

I recommend using @matt's really nice delay function.

EDIT 2:

In Swift 3, there will be new wrappers for GCD. See here: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md

The original example would be written as follows in Swift 3:

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

Note that you can write the deadlineTime declaration as DispatchTime.now() + 1.0 and get the same result because the + operator is overridden as follows (similarly for -):

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

This means that if you don't use the DispatchTimeInterval enum and just write a number, it is assumed that you are using seconds.


Swift 3+

This is super-easy and elegant in Swift 3+:

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

Older Answer:

To expand on Cezary's answer, which will execute after 1 nanosecond, I had to do the following to execute after 4 and a half seconds.

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: I discovered that my original code was slightly wrong. Implicit typing causes a compile error if you don't cast NSEC_PER_SEC to a Double.

If anyone can suggest a more optimal solution I'd be keen to hear it.