How to await x seconds with async await Swift 5.5
Asked Answered
S

2

36

How do I use the new Swift 5.5 await keyword to wait for a duration of time?

Normally, with completion handlers, you would have something like this by using DispatchQueue's asyncAfter(deadline:execute:):

func someLongTask(completion: @escaping (Int) -> Void) {
    DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
        completion(Int.random(in: 1 ... 6))
    }
}

someLongTask { diceRoll in
    print(diceRoll)
}

How can this be converted to using async & await in Swift 5.5?

Sternson answered 9/8, 2021 at 16:9 Comment(0)
S
68

iOS 16+ / macOS 13+

There's a newer API, sleep(for:tolerance:clock:), used like so:

// 3 seconds
try await Task.sleep(for: .seconds(3))

iOS <16 / macOS <13

You can use Task.sleep(nanoseconds:) to wait for a specific duration. This is measured in nanoseconds, not seconds.

Here's an example:

func someLongTask() async -> Int {
    try? await Task.sleep(nanoseconds: 1 * 1_000_000_000) // 1 second
    return Int.random(in: 1 ... 6)
}

Task {
    let diceRoll = await someLongTask()
    print(diceRoll)
}

It may be easier to use an extension for sleep so you can just pass in seconds:

extension Task where Success == Never, Failure == Never {
    static func sleep(seconds: Double) async throws {
        let duration = UInt64(seconds * 1_000_000_000)
        try await Task.sleep(nanoseconds: duration)
    }
}

Which would now be called like so:

try await Task.sleep(seconds: 1)

Note that sleep is called with try. An error is thrown if the sleep is cancelled. If you don’t care if it’s cancelled, just try? is fine.

Sternson answered 9/8, 2021 at 16:9 Comment(7)
Is the bug fixed where this wasn't actually working in the early betas?Coffelt
@Coffelt It's running fine for me now, what was the issue during early betas?Sternson
Anything longer than a few nanoseconds we wouldn't actually sleep. :) See the comments after my https://mcmap.net/q/246832/-swift-5-5-async-let-error-expression-is-39-async-39-but-is-not-marked-with-39-await-39 Anyway, glad to hear it's working now!Coffelt
@Coffelt Ah it is working now. I also just timed the example with a regular DispatchQueue and they both take the correct amount of time (roughly).Sternson
What's the reason for the where Success == Never, Failure == Never? Isn't that rather limiting?Coffelt
@Coffelt The linked documentation (in the answer) to the sleep method says: "Available when Success is Never and Failure is Never.". I found this after I couldn't get it to compile without this where clause. If there is a less limiting version, that would be better.Sternson
Yeah, this is basically the case for all the Thread static funcs so perhaps we just shouldn't worry about it.Coffelt
R
15

From iOS 16 you can use .seconds directly like this:

try await Task.sleep(for: .seconds(10))
Registrant answered 29/11, 2022 at 10:47 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.