I want to keep firing a function 5 seconds after it completes.
Previously I would use this at the end of the function:
Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { self.function() }
But I am wanting to use Swift 5.5's async/await.
If I use something like this:
func loadInfo() async {
async let info = someOtherAsyncFunc()
self.info = try? await info
await Task.sleep(5_000_000_000)
await loadInfo()
}
I get a warning that the Function call causes an infinite recursion and it's not really cancellable.
This compiles fine:
func loadInfo() async {
Task {
async let info = someOtherAsyncFunc()
self.info = try? await info
await Task.sleep(5_000_000_000)
if Task.isCancelled {
print("Cancelled")
}
else
{
print("Not cancelled")
await loadInfo()
}
}
}
and although it does fire every 5 seconds, it keeps running when my SwiftUI view is dismissed.
I start it using:
.onAppear {
loadInfo()
}
As it's all running on the same Task and not detached should it not all cancel when the view is removed?
What is the modern way to achieve this with async/await?
The point of async await is to let you write asynchronous code in a synchronous way. So you could remove the recursive function and simply write:
.task {
repeat {
// code you want to repeat
print("Tick")
try? await Task.sleep(for: .seconds(5)) // exception thrown when cancelled by SwiftUI when this view disappears.
} while (!Task.isCancelled) // if the view disappears and the above line exceptions early before 5 seconds are up, we can then check this bool to exit the loop.
print("Cancelled")
}
I noticed the print tick is always on main thread however if I move it out to its own async nonisolated func then it correctly runs on different threads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With