How to await x seconds with async await Swift 5.5
iOS 16+ / macOS 13+
There's a newer API, sleep(until:tolerance:clock:)
, used like so:
// 3 seconds
try await Task.sleep(until: .now + .seconds(3), clock: .continuous)
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.
Async/Await function without a return | Swift 5.5
This is what worked the best:
try await withUnsafeThrowingContinuation { (continuation: UnsafeContinuation<Void, Error>) in
Swift 5.5 async let - error: expression is 'async' but is not marked with 'await'
Building as a macOS command line project (Xcode: File -> New -> Project, then select "Command Line Tool" from the macOS tab), the code works perfectly. (This was a suggestion from a response in the Apple Developer Forums.)
I've added a single sleep(10)
to the end so that the command line tool doesn't exit before the async calls finish:
import Foundation
print("Hello, world!")
func doIt() async -> String {
let t = TimeInterval.random(in: 0.25 ... 2.0)
Thread.sleep(forTimeInterval: t)
return String("\(Double.random(in: 0...1000))")
}
async {
async let a = doIt()
async let b = doIt()
async let c = doIt()
async let d = doIt()
let results = await [a, b, c, d]
for result in results {
print(" \(result)")
}
}
sleep(10)
This produces the expected sort of console output (Note: the actual values will differ on every run)*:
Hello, World!
415.407747869283
574.28639828183
689.4706625185836
385.56539085197113
Program ended with exit code: 0
Problem making API request with async / await in swift 5.5
Cancellation errors for async URL session data tasks occur when the parent task is cancelled, for example if MyView is removed from the view hierarchy. Is this what is happening?
How to call async function asynchronously without awaiting for the result
This behavior will change depending upon the context.
If you invoke this from a non-isolated context, then
first
andsecond
will run on separate threads. In this scenario, thesecond
task is not actually waiting for thefirst
task, but rather there is a race as to which will finish first. This can be illustrated if you do something time-consuming in thefirst
task and you will see thesecond
task is not waiting at all.This introduces a race between
first
andsecond
and you have no assurances as which order they will run. (In my tests, it runssecond
beforefirst
most of the time, but it can still occasionally runfirst
beforesecond
.)However, if you invoke this from an actor-isolated context, then
first
will wait forsecond
to yield before running.
So, the question is, do you really care which order these two tasks start? If so, you can eliminate the race by (obviously) putting the Task { await first() }
after the call to second
. Or do you simply want to ensure that second
won’t wait for first
to finish? In that case, this already is the behavior and no change to your code is required.
You asked:
What if
await first()
needs to be run on the same queue assecond()
but asynchronously. … I am just thinking [that if it runs on background thread that it] would mean crashes due to updates of UI not from the main thread.
You can mark the routine to update the UI with @MainActor
, which will cause it to run on the main thread. But note, do not use this qualifier with the time-consuming task, itself (because you do not want to block the main thread), but rather decouple the time-consuming operation from the UI update, and just mark the latter as @MainActor
.
E.g., here is an example that manually calculates π asynchronously, and updates the UI when it is done:
func startCalculation() {
Task {
let pi = await calculatePi()
updateWithResults(pi)
}
updateThatCalculationIsUnderway() // this really should go before the Task to eliminate any races, but just to illustrate that this second routine really does not wait
}
// deliberately inefficient calculation of pi
func calculatePi() async -> Double {
await Task.detached {
var value: Double = 0
var denominator: Double = 1
var sign: Double = 1
var increment: Double = 0
repeat {
increment = 4 / denominator
value += sign * 4 / denominator
denominator += 2
sign *= -1
} while increment > 0.000000001
return value
}.value
}
func updateThatCalculationIsUnderway() {
statusLabel.text = "Calculating π"
}
@MainActor
func updateWithResults(_ value: Double) {
statusLabel.text = "Done"
resultLabel.text = formatter.string(for: value)
}
Note: To ensure this slow synchronous calculation of calculatePi
is not run on the current actor (presumably the main actor), we want an “unstructured task”. Specifically, we want a “detached task”, i.e., one that is not run on the current actor. As the Unstructured Concurrency section of The Swift Programming Language: Concurrency: Tasks and Task Groups says:
To create an unstructured task that runs on the current actor, call the
Task.init(priority:operation:)
initializer. To create an unstructured task that’s not part of the current actor, known more specifically as a detached task, call theTask.detached(priority:operation:)
class method.
Swiftui async / await with Firebase
You are calling getDocuments
with a completion handler.
You cannot mix Swift structured concurrency async/await
directly with getDocuments
/ completion handler. async/await
and completion handler are opposites.
Everything about your completion handler is wrong. You cannot throw from a completion handler. You cannot return anything from a completion handler. That's the whole point of async/await
. That is why async/await
supersedes completion handlers.
To wrap async/await
around a completion handler call, you must use withUnsafeThrowingContinuation
.
async' call in a function that does not support concurrency swift ios Xcode async/await
The answer here is that the "await getSomethingLater" must be called from an async context. Literally that means changing this:
let result = await tryThis.getSomethingLater(3.141592653589793238462)
print("result: \(result)")
into this:
Task {
let result = await tryThis.getSomethingLater(3.141592653589793238462)
print("result: \(result)")
}
So the whole thing becomes:
class TryThis {
func getSomethingLater(_ number: Double) async -> String {
// test - sleep for 3 seconds, then return
Thread.sleep(forTimeInterval: 3)
return String(format: ">>>%8.2f<<<", number)
}
}
let tryThis = TryThis()
Task {
let result = await tryThis.getSomethingLater(3.141592653589793238462)
print("result: \(result)")
}
Here's the output:
result: >>> 3.14<<<
There's great info in the Meet async/await in Swift video from WWDC21.
How to trigger action after x seconds in swiftUI
Create a delay, which then sets the @State
property hasTimeElapsed
to true
when the time has elapsed, updating the view body.
With Swift 5.5 and the new concurrency updates (async
& await
), you can now use task(_:)
like the following:
struct ContentView: View {
@State private var hasTimeElapsed = false
var body: some View {
Text(hasTimeElapsed ? "Sorry, too late." : "Please enter above.")
.task(delayText)
}
private func delayText() async {
// Delay of 7.5 seconds (1 second = 1_000_000_000 nanoseconds)
try? await Task.sleep(nanoseconds: 7_500_000_000)
hasTimeElapsed = true
}
}
See more info about Task.sleep(nanoseconds:)
in this answer.
Older versions
Xcode 13.0+ now supports concurrency, backwards compatible! However, here is still the 'old' way to do it:
You can use DispatchQueue
to delay something. Trigger it with onAppear(perform:)
(which happens when the view first appears). You could also hook the delay up to a Button instead if wanted.
Example:
struct ContentView: View {
@State private var hasTimeElapsed = false
var body: some View {
Text(hasTimeElapsed ? "Sorry, too late." : "Please enter above.")
.onAppear(perform: delayText)
}
private func delayText() {
// Delay of 7.5 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 7.5) {
hasTimeElapsed = true
}
}
}
How to create a delay in Swift?
Instead of a sleep, which will lock up your program if called from the UI thread, consider using NSTimer
or a dispatch timer.
But, if you really need a delay in the current thread:
do {
sleep(4)
}
This uses the sleep
function from UNIX.
Related Topics
Disable Https Get Certificate Check in Swift 5
How to "Explicitly" Implement a Protocol in Swift? If It Is Impossible, Why
Button State Activates on Wrong Cells
Crash When Running on Device After Second Launch
Attributed Text, Replace a Specific Font by Another Using Swift
JSONencoder and Propertylistencoder Don't Conform to Encoder
Xcode: Using Custom Fonts Inside Dynamic Framework
Accessing Global Variable in Swift
How to Save a Custom Class as an Attribute of a Coredata Entity in Swift 3
Capturing a Struct Reference in a Closure Doesn't Allow Mutations to Occur
Initializing Property via Closure
Hovering a Modelentity in Front of Arcamera
Decode Dictionary with Random Initial Key
Why Is Casting a Struct to Anyobject Not a Compile Error in Swift
How to Connect Outlets and Actions in Swift/Macos Programaticly