30
Apr
2022
SwiftUI Delay Action on Appear
Reading time: 1 min
This recipe shows how to perform delayed actions in SwiftUI. It also shows examples of how to implement a delayed onAppear for async and non-async blocks.
The end result looks like this:
There are two ways to delay actions in Swift in general:
- Using
DispatchQueue
withasyncAfter
with a non-async block:
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(5)) {
// delayed action
}
- Using an
async
block withTask.sleep
:
func myFunc() async {
try? await Task.sleep(nanoseconds: UInt64(5 * 1E9))
// delayed action
}
The most common use-case of delayed actions in SwiftUI is to perform an action when the view appears after a fixed period of time. Here are a few extensions that implement delayed onAppear
:
extension View {
// sync block on a DispatchQueue at specified deadline
func perform(on queue: DispatchQueue = .main,
at deadline: DispatchTime,
action: @escaping () -> Void) -> some View {
onAppear {
queue.asyncAfter(deadline: deadline, execute: action)
}
}
// sync block on a DispatchQueue after the specified interval
func perform(on queue: DispatchQueue = .main,
after interval: TimeInterval,
action: @escaping () -> Void) -> some View {
perform(on: queue, at: .now() + interval, action: action)
}
// async block on main thread after the specified interval
func perform(after interval: TimeInterval,
action: @escaping @Sendable () async -> Void) -> some View {
task {
try? await Task.sleep(nanoseconds: UInt64(interval * 1E9))
await action()
}
}
}
And here are all three in action:
@State private var text = "Wait for it..."
var body: some View {
Text(text)
.perform(at: .now() + .seconds(2)) {
text = "2 seconds passed"
}
.perform(after: 4) {
text = "4 seconds passed"
}
.perform(after: 3) {
try? await Task.sleep(nanoseconds: UInt64(3 * 1E9))
text = "6 seconds passed in total"
}
}