571

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?#>)
Kumar KL
  • 15,086
  • 9
  • 36
  • 57
  • 1
    Apple unpublished this book in 2018. [Latest archive I could find is from December 2017](https://web.archive.org/web/20171227051224/https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/index.html). Old links to the iBook now simply redirect to https://developer.apple.com/documentation/swift. – Cœur Dec 29 '18 at 05:56

26 Answers26

1103

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)
}
matt
  • 447,615
  • 74
  • 748
  • 977
  • 2
    I just needed shortcut for the delay calculation, ended up with: `func delayInSec(delay: Double) -> dispatch_time_t { return dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))) }` – Aviel Gross Aug 20 '14 at 15:31
  • Would `delay(0.0) { /*stuff*/ }` (insert appropriate linebreaks) be a valid command if I wanted to do something on the main thread without any delay (such as modify the GUI)? – Matt Aug 21 '14 at 19:40
  • 1
    @Matt You tell me. You're looking at the code. What's the problem? Or if you're in doubt, call `dispatch_async` onto the main thread yourself. Again, what's the problem? – matt Aug 21 '14 at 21:38
  • 1
    I love this usage. Similarly, you can do: func onMainQueue(closure:()->()){ NSOperationQueue.mainQueue().addOperationWithBlock(closure) } – Glenn Howes Sep 07 '14 at 20:42
  • 1
    It's not a bug and it has nothing to do with my `delay` function. And `->()` is the same thing as `->Void` isn't it? It's just a closure "feature". I run into this all the time with closures. Basically just don't write any one-line closures, because Swift will try to treat this as syntactic sugar for returning the result of that expression. – matt Oct 01 '14 at 21:12
  • 1
    @matt Thanks for this code. It was working fine, but now I am getting the error, "Cannot convert the expression's type (FloatLiteralConvertible, () -> () -> $T3)' to type 'FloatLiteralConvertible' - Do you have any ideas why? Thanks ... – agf119105 Oct 05 '14 at 21:18
  • 4
    @agf119105 If you have just one line of code in the closure, add another line of code (e.g. `return`). – matt Oct 05 '14 at 21:54
  • how could we weakify self here? is self strongly retained? – Gaston Morixe Jan 02 '15 at 10:52
  • 2
    @GastonM Irrelevant. Passing a function has _of itself_ no memory management issues. – matt Jan 02 '15 at 15:14
  • 1
    @matt - This is great, but forgive my ignorance: where do I put this code to make it a top-level function? Thanks. – Mike Taverne Feb 05 '15 at 17:46
  • @MikeTaverne At top level! (Of a swift file.) http://www.apeth.com/swiftBook/ch01.html#_the_structure_of_a_swift_file – matt Feb 05 '15 at 17:56
  • 7
    "A language where you can improve the language". I don't understand how defining a global function is improving the language, or why this isn't doable in C even. Maybe if you overload an operator ;) `1.0 ~~ { code...}` – Yerk Jun 18 '15 at 20:04
  • You could make it even better with a 0 default value to the delay parameter. This way you can also write `delay { //do stuff }` If you just need the execution to happen later – Antzi Aug 04 '15 at 12:58
  • 8
    Not questioning the correctness of your answer—but isn't *"I use dispatch_after so often"* a code smell which would best be fought by **not** providing a convenience function? – Nikolai Ruhe Sep 24 '15 at 07:36
  • @matt If this was called on global queue would it be less accurate? Or can it be on any queue and maintain the same accuracy and precision as when called on main queue? Thanks – MikeG Jan 30 '16 at 03:19
  • 1
    @matt It would be great to use NSTimeInterval typealias for Double in this case. – Shmidt Feb 26 '16 at 15:20
  • NikolaiRuhe: No "code smell", but a nasal problem. @MikeG: Actually, it would be more accurate on a background queue. On a background queue, you have multiple threads and one can start _exactly_ when you ask. On the main queue, any task that is executing at the exact dispatch time will finish first. – gnasher729 May 27 '16 at 22:14
  • You can simplify it to `let when = DispatchTime.now() + delay` in Swift 3 :) – Btw, I wonder what the function parameters should be called in accordance with https://swift.org/documentation/api-design-guidelines/. Perhaps `delay(for:execute:)` ? – Martin R Jun 15 '16 at 11:44
  • @MartinR Yes, thanks, I was just getting around to that. I don't understand what the migrator was thinking here... — I never liked `closure` but probably no one will ever see or use it, as they'll be using trailing closure syntax. And I like having no first parameter. – matt Jun 15 '16 at 13:53
  • @NikolaiRuhe Hmmmm... I use a dispatch after .001 for `do on the next run loop` so as to let stuff get set up. In truth, that should be all handled by the `viewDidDisappear` and all those methods, but sometimes passing a block around so someone else can execute it turns into even more cumbersome code. – Dan Rosenstark Jun 16 '16 at 00:27
  • `DispatchQueue.main.asyncAfter(deadline: when, execute: closure),` giver error that Dispatch Queue have no member `asyncAfter` – rptwsthi Aug 14 '16 at 21:25
  • @rptwsthi Did you read what I said? Xcode 8, seed 4. You have not updated to Xcode 8 seed 4 (or seed 5). – matt Aug 15 '16 at 00:06
  • How would you go about stopping the closure from executing. I am trying to do like a timer and every second a UILabel updates but if a user touches a certain button then the timer goes away. – Cody Weaver Aug 31 '16 at 15:19
  • @CodyWeaver Then use a timer. I've explained elsewhere how to write a cancelable timer using GCD. – matt Aug 31 '16 at 16:22
  • In Swift 3, `@escaping` must be explicitly written in the code? – JW.ZG Sep 13 '16 at 02:17
757

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.

Community
  • 1
  • 1
Cezary Wojcik
  • 21,065
  • 6
  • 34
  • 36
  • 18
    Tip: Because the block is the final parameter to the function, you can use Swift's "trailing closure" syntax for extra readability: `dispatch_after(1, dispatch_get_main_queue()) { println("test") }` – Bill Jun 05 '14 at 01:37
  • 8
    I think using the number `1` in `dispatch_after(1, ...` may cause a lot of confusion here. People will think it is a number of seconds, when it actually is **nano-second**. I suggest see @brindy 's answer on how to create this number properly. – Hlung Aug 27 '14 at 18:16
  • 4
    Please change `1` to `dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC)))` because it leads to confusion. People could think that you don't need to create a dispatch_time_t in Swift – OemerA Nov 08 '14 at 12:17
  • 4
    The Swift 3 version doesn't appear to be working. It complaints that `Binary operator '+' cannot be applied to operands of type DispatchTime and '_'` on the line `let delayTime = DispatchTime.now() + .seconds(1.0)` – Andy Ibanez Jun 24 '16 at 23:21
  • 10
    Rewriting it as `DispatchTime.now() + 1.0` seems to be the only way to make it work (no need for `.seconds`) – Andy Ibanez Jun 24 '16 at 23:23
  • Thanks - updated the answer. The issue was actually that `DispatchTimeInterval.seconds` has an associated value of `Int`, so `let delayTime = DispatchTime.now + .seconds(1)` works. – Cezary Wojcik Jun 24 '16 at 23:41
  • 1
    As of Swift 3 beta 4, `after` is renamed to `asyncAfter`, and its parameter `when` is renamed to `deadline`. – ArVID220u Aug 01 '16 at 20:21
  • `.seconds` needs a value of `Int`, if you require a double value, use `.milliseconds` instead. e.g. `+ .milliseconds(1500)` is more swifty than `+ 1.5` – Shawn Apr 26 '17 at 03:24
137

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.

brindy
  • 3,986
  • 2
  • 20
  • 25
  • I get a compiler error for a deprecated API with `dispatch_get_current_queue()`. I used `dispatch_get_main_queue()` instead. – David L Jul 19 '14 at 14:05
  • @DavidL - thanks, `dispatch_get_main_queue()` is definitely what you should be using. Will update. – brindy Jul 19 '14 at 14:22
  • i tried this in a playground with swift 3 and it doesn't work – μολὼν.λαβέ Dec 22 '16 at 21:59
  • @GAlexander Works for me. Are you allowing the playground to execute indefinitely? – brindy Dec 22 '16 at 22:20
  • uhm, well no, i let run run for a couple of hours and still nothing printed. here's what i used. "import Dispatch import Darwin import CoreGraphics 'DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) { print(" got here ") } " – μολὼν.λαβέ Dec 22 '16 at 23:04
  • @GAlexander ah - you have to explicitly tell the Playground to allow indefinite execution. See http://stackoverflow.com/a/33536290/73479 – brindy Dec 23 '16 at 07:36
  • You should move your Swift 3+ code to the top of the answer. Or even delete the old code. – pkamb Jun 11 '19 at 18:38
83

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

Community
  • 1
  • 1
Waam
  • 931
  • 6
  • 6
  • 1
    The one performance feature that has performSelector:afterDelay is ability to cancel it. Only this solution covers the problem. Thanks – HotJard Jun 05 '15 at 20:34
  • @HotJard Note that `performSelector:afterDelay:` is now available in Swift 2, so you can cancel it. – matt Nov 28 '15 at 22:52
  • @matt but it's available only for NSObject, isn't it? – HotJard Dec 01 '15 at 13:18
  • @HotJard Sure but that's better than not having it at all. I see no issue there. However, just as with this answer, I had already compensated for its loss by writing a GCD-based cancelable timer (using a `dispatch_source_t`, because that's something you can cancel). – matt Dec 01 '15 at 16:43
  • how would I make this so that I can call `delay(1.0) { cancel_delay(retVal) }` from another method such as didSelectRowAtIndexPath...? – MikeG Feb 05 '16 at 22:44
  • 2
    Thanks a lot, I've been using this up to Swift 2.3. Swift 3.0 compiler is complaining now, would be great if you updated your answer! – nontomatic Sep 14 '16 at 12:04
  • I don't know this has to be so complicated as of Swift 5.x – Subzero Jul 09 '20 at 03:11
30

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
}
Sazzad Hissain Khan
  • 29,428
  • 20
  • 134
  • 192
Vakas
  • 5,382
  • 3
  • 33
  • 44
22

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#>
}
Senseful
  • 73,679
  • 56
  • 267
  • 405
14

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.

garafajon
  • 949
  • 8
  • 12
8

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")
    }
Mohammad Sadiq Shaikh
  • 2,886
  • 8
  • 32
  • 53
4

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

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

//Compact Form

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) {
    //Code here
 }
}
Nagarjun
  • 5,811
  • 5
  • 28
  • 47
A.G
  • 13,048
  • 84
  • 61
4

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")
}
Himanshu Mahajan
  • 4,458
  • 2
  • 28
  • 29
4

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!
    }
Zgpeace
  • 1,989
  • 15
  • 20
3

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.

Community
  • 1
  • 1
Suragch
  • 364,799
  • 232
  • 1,155
  • 1,198
3

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()
                }
            }
Rahul Singha Roy
  • 532
  • 1
  • 3
  • 13
2

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);
});
Pang
  • 8,605
  • 144
  • 77
  • 113
garg
  • 2,344
  • 20
  • 20
2

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")
}
Suhit Patil
  • 10,286
  • 2
  • 42
  • 54
1

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
}
Jeehut
  • 15,556
  • 7
  • 54
  • 70
1

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
}
Hardeep Singh
  • 942
  • 8
  • 15
1

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())
}
Sanjay Mali
  • 397
  • 4
  • 12
1
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

Sangram Shivankar
  • 3,245
  • 3
  • 22
  • 36
CrazyPro007
  • 692
  • 4
  • 13
1

In Swift 4

Use this snippet:

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

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")
}
Himanshu Mahajan
  • 4,458
  • 2
  • 28
  • 29
0

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")
}
Tim
  • 1,180
  • 1
  • 8
  • 8
  • Apple has given us all needed to use GCD in few lines. Why to bother with pods, workspace and so on? Simply read docs about @escaping and capturing. it is enough. – ingconti Jan 17 '18 at 21:54
0

Swift 4 has a pretty short way of doing this:

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

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()))
}
Maxim Makhun
  • 2,084
  • 1
  • 20
  • 29
0

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())
}
Mojtaba Hosseini
  • 47,708
  • 12
  • 157
  • 176
-1

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