416

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?

0

8 Answers 8

1177

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.

Sign up to request clarification or add additional context in comments.

9 Comments

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)".
@OctavioAntonioCedeño Happy to help. This really bugged me for a while :D
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.
@jiawen 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.
Working on iOS 11 and Swift 4!
|
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.

1 Comment

plus one for the Timer comparison and the disclaimer about the main runloop!
61

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 } 

2 Comments

You basically just copied this answer but yes this is good, thanks.
How to cancel this?
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 } 

2 Comments

First way displays have error "Use of unresolved identifier 'delay'"
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.
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 } 

2 Comments

sleep(3) worked for me. Got a compilation error on usleep.
usleep needs and argument, of course, @AbdurrahmanMubeenAli. Something like usleep(3000000).
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 } 

Comments

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 } 

Comments

1

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) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.