dispatch_after - GCD in Swift?

Objective CSwiftGrand Central-Dispatch

Objective C Problem Overview


I've gone through the iBook from Apple, and couldn't find any definition of it:

Can someone explain the structure of dispatch_after?

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

Objective C Solutions


Solution 1 - Objective C

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

Solution 2 - Objective C

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.

Solution 3 - Objective C

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.

Solution 4 - Objective C

matt's syntax is very nice and if you need to invalidate the block, you may want to use this :

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

Use as follow

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

credits

Link above seems to be down. Original Objc code from Github

Solution 5 - Objective C

Simplest solution in Swift 3.0 & Swift 4.0 & Swift 5.0

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

Usage

delayWithSeconds(1) {
   //Do something
}

Solution 6 - Objective C

Apple has a dispatch_after snippet for 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#>
});

Here is the same snippet ported to Swift 3:

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

Solution 7 - Objective C

Another way is to extend Double like this:

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

Then you can use it like this:

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

I like matt's delay function but just out of preference I'd rather limit passing closures around.

Solution 8 - Objective C

In Swift 3.0

Dispatch queues

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

Dispatch after 5 seconds

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

Solution 9 - Objective C

  1. Add this method as a part of UIViewController Extension.

    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) } } Call this method on VC:

     self.runAfterDelay(5.0, block: {
      //Add code to this block
     	print("run After Delay Success")
     })
    
performSelector("yourMethod Name", withObject: nil, afterDelay: 1)
override func viewWillAppear(animated: Bool) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in
	//Code Here
})

//Compact Form

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
	//Code here
 }
}

Solution 10 - Objective C

Although not the original question by the OP, certain NSTimer related questions have been marked as duplicates of this question, so it is worth including an NSTimer answer here.

#NSTimer vs dispatch_after

  • NSTimer is more high level while dispatch_after is more low level.
  • NSTimer is easier to cancel. Canceling dispatch_after requires writing more code.

#Delaying a task with NSTimer

Create an NSTimer instance.

var timer = NSTimer()

Start the timer with the delay that you need.

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

Add a function to be called after the delay (using whatever name you used for the selector parameter above).

func delayedAction() {
    print("Delayed action has now started."
}

#Notes

  • If you need to cancel the action before it happens, simply call timer.invalidate().

  • For a repeated action use repeats: true.

  • If you have a one time event with no need to cancel then there is no need to create the timer instance variable. The following will suffice:

      NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) 
    
  • See my fuller answer here.

Solution 11 - Objective C

Swift 3.0 version

Following closure function execute some task after delay on main thread.

func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){

    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
       onCompletion()
    })
}

Call this function like:

performAfterDelay(delay: 4.0) {
  print("test")
}

Solution 12 - Objective C

In Swift 5, use in the below:

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: closure) 
  
// time gap, specify unit is second
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
            Singleton.shared().printDate()
        }
// default time gap is second, you can reduce it
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
          // just do it!
    }

Solution 13 - Objective C

For multiple functions use this. This is very helpful to use animations or Activity loader for static functions or any UI Update.

DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) {
            // Call your function 1
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                // Call your function 2
            }
        }

For example - Use a animation before a tableView reloads. Or any other UI update after the 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()
                }
            }

Solution 14 - Objective C

This worked for me.

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

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

Solution 15 - Objective C

Swift 3 & 4:

You can create a extension on DispatchQueue and add function delay which uses DispatchQueue asyncAfter function internally

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

use:

DispatchQueue.delay(.seconds(1)) {
    print("This is after delay")
}

Solution 16 - Objective C

Another helper to delay your code that is 100% Swift in usage and optionally allows for choosing a different thread to run your delayed code from:

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

Now you simply delay your code on the Main thread like this:

delay(bySeconds: 1.5) { 
    // delayed code
}

If you want to delay your code to a different thread:

delay(bySeconds: 1.5, dispatchLevel: .background) { 
    // delayed code that will run on background thread
}

If you prefer a Framework that also has some more handy features then checkout HandySwift. You can add it to your project via Carthage then use it exactly like in the examples above, e.g.:

import HandySwift    

delay(bySeconds: 1.5) { 
    // delayed code
}

Solution 17 - Objective C

I always prefer to use extension instead of free functions.

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

Use as follow.

DispatchQueue.performAction(after: 0.3) {
  // Code Here
}

Solution 18 - Objective C

Delaying GCD call using asyncAfter in swift

let delayQueue = DispatchQueue(label: "com.theappmaker.in", qos: .userInitiated)
let additionalTime: DispatchTimeInterval = .seconds(2)

**We can delay as microseconds,milliseconds,nanoseconds

delayQueue.asyncAfter(deadline: .now() + 0.60) {
    print(Date())
}

delayQueue.asyncAfter(deadline: .now() + additionalTime) {
    print(Date())
}

Solution 19 - Objective C

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // ...
});

The dispatch_after(_:_:_:) function takes three parameters:

> a delay
> a dispatch queue
> a block or closure

The dispatch_after(_:_:_:) function invokes the block or closure on the dispatch queue that is passed to the function after a given delay. Note that the delay is created using the dispatch_time(_:_:) function. Remember this because we also use this function in Swift.

I recommend to go through the tutorial Raywenderlich Dispatch tutorial

Solution 20 - Objective C

In Swift 4

Use this snippet:

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

Solution 21 - Objective C

Here is synchronous version of 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()

Along with asynchronous one:

let deadline = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadline) {
    dispatchPrecondition(condition: .onQueue(DispatchQueue.global()))
}

Solution 22 - Objective C

use this code to perform some UI related task after 2.0 seconds.

            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

Following closure function execute some task after delay on main thread.

func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){

    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: {
       onCompletion()
    })
}

Call this function like:

performAfterDelay(delay: 4.0) {
  print("test")
}

Solution 23 - Objective C

Now more than syntactic sugar for asynchronous dispatches in Grand Central Dispatch (GCD) in Swift.

add Podfile

pod 'AsyncSwift'

Then,you can use it like this.

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

Solution 24 - Objective C

Swift 4 has a pretty short way of doing this:

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

Solution 25 - Objective C

Preserve the current queue!

Besides good answers of this question, you may also consider preserving the current queue to prevent unnecessarily main queue operations (for example when you are trying to delay some async operations).

func after(_ delay: TimeInterval,
           perform block: @escaping ()->(),
           on queue: DispatchQueue = OperationQueue.current?.underlyingQueue ?? .main) { // So this `queue` preserves the current queue and defaulted to the `main`. Also the caller can pass in the desired queue explicitly
    queue.asyncAfter(deadline: .now() + delay, execute: block)
}
Usage:
after(3) {
    // will be executed on the caller's queue
    print(Date())
}

Solution 26 - Objective C

To execute a funtion or code after a delay use the next method

DispatchQueue.main.asyncAfter(deadline: .now() + 'secondsOfDelay') {
        your code here...
    }

Example - In this example the funtion getShowMovies will be executed after 1 second

DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
        self.getShowMovies()
    }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKumar KLView Question on Stackoverflow
Solution 1 - Objective CmattView Answer on Stackoverflow
Solution 2 - Objective CCezary WojcikView Answer on Stackoverflow
Solution 3 - Objective CbrindyView Answer on Stackoverflow
Solution 4 - Objective CWaamView Answer on Stackoverflow
Solution 5 - Objective CVakasView Answer on Stackoverflow
Solution 6 - Objective CSensefulView Answer on Stackoverflow
Solution 7 - Objective CgarafajonView Answer on Stackoverflow
Solution 8 - Objective CMohammad Sadiq ShaikhView Answer on Stackoverflow
Solution 9 - Objective CAlvin GeorgeView Answer on Stackoverflow
Solution 10 - Objective CSuragchView Answer on Stackoverflow
Solution 11 - Objective CHimanshu MahajanView Answer on Stackoverflow
Solution 12 - Objective CZgpeaceView Answer on Stackoverflow
Solution 13 - Objective CRahul Singha RoyView Answer on Stackoverflow
Solution 14 - Objective CgargView Answer on Stackoverflow
Solution 15 - Objective CSuhit PatilView Answer on Stackoverflow
Solution 16 - Objective CJeehutView Answer on Stackoverflow
Solution 17 - Objective CHardeep SinghView Answer on Stackoverflow
Solution 18 - Objective CSanjay MaliView Answer on Stackoverflow
Solution 19 - Objective CCrazyPro007View Answer on Stackoverflow
Solution 20 - Objective CBlackRockView Answer on Stackoverflow
Solution 21 - Objective CMaxim MakhunView Answer on Stackoverflow
Solution 22 - Objective CHimanshu MahajanView Answer on Stackoverflow
Solution 23 - Objective CTimView Answer on Stackoverflow
Solution 24 - Objective CVlady VeselinovView Answer on Stackoverflow
Solution 25 - Objective CMojtaba HosseiniView Answer on Stackoverflow
Solution 26 - Objective CIker SolozabalView Answer on Stackoverflow