owlswipe
owlswipe

Reputation: 19469

How to program a delay in Swift 3

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?

Upvotes: 414

Views: 384316

Answers (8)

leo
leo

Reputation: 113

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)

Upvotes: 1

Paul B
Paul B

Reputation: 5125

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
}

Upvotes: 7

Victor Do
Victor Do

Reputation: 2257

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.

Upvotes: 217

Zohaib Brohi
Zohaib Brohi

Reputation: 41

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
}

Upvotes: 4

owlswipe
owlswipe

Reputation: 19469

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.

Upvotes: 1172

Anand Verma
Anand Verma

Reputation: 592

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
}

Upvotes: 14

Pratyush Pratik Sinha
Pratyush Pratik Sinha

Reputation: 714

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

Upvotes: 1

Vakas
Vakas

Reputation: 6472

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
}

Upvotes: 61

Related Questions