Calling a Method After Delay - codepath/ios_guides GitHub Wiki
When prototyping or orchestrating animations, it is sometimes useful to run a method after some delay.
Using DispatchQueue.asyncAfter
The standard pattern in modern Swift is to call DispatchQueue.main.asyncAfter(deadline:execute:) directly. Since the code in the braces is a closure, you have to use self to refer to your class methods and variables.
// Delay for 2 seconds, then run the code between the braces.
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
// This code will run on the main queue after the delay
}
For better readability with non-integer units, you can also use .seconds, .milliseconds, or other DispatchTimeInterval cases:
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
// Runs 500 ms from now
}
Using structured concurrency
From a synchronous context, you can wrap the delay in a Task and call Task.sleep(nanoseconds:) (iOS 13+). Unlike Thread.sleep, it suspends the current task without blocking a thread, and it respects cancellation:
Task {
try await Task.sleep(nanoseconds: 2_000_000_000) // 2 seconds
// This code runs after the delay
}
On iOS 16+, you can use the Duration-based overload Task.sleep(for:) for readability:
Task {
try await Task.sleep(for: .seconds(2))
}
Task { ... } starts a new top-level task. It inherits the surrounding actor context only when created from an actor-isolated context (for example, inside a @MainActor-isolated method); otherwise the task body runs on the cooperative thread pool. If you need to update UI after the delay, hop to the main actor explicitly with await MainActor.run { ... } (or annotate the surrounding code with @MainActor).