How to program a delay in Swift 3
Asked Answered
A

8

412

In earlier versions of Swift, one could create a delay with the following code:

let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
    //put your code which should be executed with a delay here
}

But now, in Swift 3, Xcode automatically changes 6 different things but then the following error appears: "Cannot convert DispatchTime.now to expected value dispatch_time_t aka UInt64."

How can one create a delay before running a sequence of code in Swift 3?

Ashurbanipal answered 25/6, 2016 at 17:30 Comment(0)
A
1165

After a lot of research, I finally figured this one out.

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { // Change `2.0` to the desired number of seconds.
   // Code you want to be delayed
}

This creates the desired "wait" effect in Swift 3 and Swift 4.

Inspired by a part of this answer.

Ashurbanipal answered 25/6, 2016 at 17:30 Comment(9)
You could make your code a bit more swifty by replacing "+ 2" with "+ .seconds(2)". Or, for the ultimate in swiftyness, you could drop the first line and replace "deadline: when" with "deadline: .now() + .seconds(2)".Juetta
@OctavioAntonioCedeño Happy to help. This really bugged me for a while :DAshurbanipal
if the delay is long, say 10 min, and the phone goes to sleep. the task will never be run even after the phone is woken up after 10 min.Psalter
@Psalter That's true, but that would be the case with any such delay. I can't think of a use case other than notifications where this could be an issue, and for waiting to send a notification you should definitely use .firedate instead.Ashurbanipal
but this function available iOS (10.0 and later)Pishogue
@Pishogue Yep, it's working on iOS 10 + Swift 3. I'll check about iOS 11 and Swift 4 when they come out as final releases.Ashurbanipal
Working on iOS 11 and Swift 4!Ashurbanipal
I've got a problem with this answer, I wanted to trigger a code every second or less and it came out that it's not called exactly one second and there are discrepancies: #49347950Chop
@codddeer123 I suspect what's happening asynchronously may not be happening on time! The answer in your question there should explain more in detail.Ashurbanipal
J
217

I like one-line notation for GCD, it's more elegant:

    DispatchQueue.main.asyncAfter(deadline: .now() + 42.0) {
        // do stuff 42 seconds later
    }

Also, in iOS 10 we have new Timer methods, e.g. block initializer:

(so delayed action may be canceled)

    let timer = Timer.scheduledTimer(withTimeInterval: 42.0, repeats: false) { (timer) in
        // do stuff 42 seconds later
    }

Btw, keep in mind: by default, timer is added to the default run loop mode. It means timer may be frozen when the user is interacting with the UI of your app (for example, when scrolling a UIScrollView) You can solve this issue by adding the timer to the specific run loop mode:

RunLoop.current.add(timer, forMode: .common)

At this blog post you can find more details.

Jumna answered 31/10, 2016 at 21:9 Comment(1)
plus one for the Timer comparison and the disclaimer about the main runloop!Rove
N
60

Try the following function implemented in Swift 3.0 and above

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

Usage

delayWithSeconds(1) {
   //Do something
}
Novanovaculite answered 24/10, 2016 at 6:4 Comment(2)
You basically just copied this answer but yes this is good, thanks.Ashurbanipal
How to cancel this?Polychromatic
K
14

Try the below code for delay

//MARK: First Way

func delayForWork() {
    delay(3.0) {
        print("delay for 3.0 second")
    }
}

delayForWork()

// MARK: Second Way

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
    // your code here delayed by 0.5 seconds
}
Kristopherkristos answered 31/5, 2018 at 12:18 Comment(2)
First way displays have error "Use of unresolved identifier 'delay'"Extradite
This programmer is working with a helper method in his code base and has for a long time. So delay was code he has used for a while not knowing it is not apart of Apple's SDK.Reareace
Z
7

Most common things to use are asyncAfter() and Timer. But if blocking thread is OK, then there is an option:

sleep(3) // in seconds
usleep   // in 1/million of second 

For asynchronous programming (Swift 5.5) pausing in func looks like this:

func someAsyncFunc() async {
    await Task.sleep(2_000_000_000)  // Two seconds
    // Code to be executed with a delay here
}
Zipporah answered 31/10, 2021 at 17:21 Comment(2)
sleep(3) worked for me. Got a compilation error on usleep.Jacobo
usleep needs and argument, of course, @AbdurrahmanMubeenAli. Something like usleep(3000000).Zipporah
C
4

One way is to use DispatchQueue.main.asyncAfter as a lot of people have answered.

Another way is to use perform(_:with:afterDelay:). More details here

perform(#selector(delayedFunc), with: nil, afterDelay: 3)

@IBAction func delayedFunc() {
    // implement code
}
Creepy answered 25/7, 2019 at 11:9 Comment(0)
P
1

//Runs function after x seconds

public static func runThisAfterDelay(seconds: Double, after: @escaping () -> Void) {
    runThisAfterDelay(seconds: seconds, queue: DispatchQueue.main, after: after)
}

public static func runThisAfterDelay(seconds: Double, queue: DispatchQueue, after: @escaping () -> Void) {
    let time = DispatchTime.now() + Double(Int64(seconds * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
    queue.asyncAfter(deadline: time, execute: after)
}

//Use:-

runThisAfterDelay(seconds: x){
  //write your code here
}
Psycho answered 28/2, 2018 at 13:9 Comment(0)
C
0

UI can also use Task as shown in MultiNodeTestConductor.swift:

/// puse execution by the given druation
private func delayUiUpdate(duration: Double) async {
    do {
        try await Task.sleep(until: .now + .seconds(duration), clock: .continuous)
    } catch {
        logger.error("Task delay error \(error.localizedDescription)")
    }
}

You call it like this:

await delayUiUpdate(duration: 2)
Christenson answered 17/8, 2023 at 17:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.