"Wait a second": why delays in Swift are magic, not hacks
\n\nImagine: you're writing a pizza ordering app. The user clicks "Pay", and instantly — bam! — the money is deducted. No animation, no pause, no feeling that "something is happening." The user gets scared, closes the app, and you lose a customer. Delay in Swift is not a crutch, but a tool for UX design and proper architecture.
\n\nThe question "How to create a delay in Swift?" on Stack Overflow has gathered tens of thousands of views. And it's no wonder: beginners try to use sleep() (spoiler: you can't do that), while pros look for elegant solutions. We'll break down 5 working methods — from classic GCD to modern async/await. Let's go!
1. The Classic: DispatchQueue.main.asyncAfter (iOS 4+)
\nThe most popular way to create a delay in Swift is DispatchQueue.main.asyncAfter. It works on any iOS version and requires no additional imports. It's suitable for executing code on the main thread (e.g., updating the UI).
import UIKit\n\nclass ViewController: UIViewController {\n override func viewDidLoad() {\n super.viewDidLoad()\n \n // 2-second delay\n DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {\n print("2 seconds have passed!")\n self.showAlert()\n }\n }\n \n func showAlert() {\n let alert = UIAlertController(title: "Hello!", message: "This is a delay", preferredStyle: .alert)\n alert.addAction(UIAlertAction(title: "OK", style: .default))\n present(alert, animated: true)\n }\n}\n\nPros and Cons
\n- \n
- Pros: simplicity, backward compatibility, works on the main thread. \n
- Cons: cannot cancel the delay (unless you save the DispatchWorkItem). \n
2. Cancellable Delay via DispatchWorkItem
\nSometimes you need to cancel a delay — for example, if the user leaves the screen. DispatchWorkItem solves this problem. Save a reference to the "work" and call cancel().
class DelayedTask {\n private var workItem: DispatchWorkItem?\n \n func scheduleDelayedAction() {\n // Create the task\n let item = DispatchWorkItem { [weak self] in\n print("Task executed after delay")\n self?.doSomething()\n }\n \n // Save and execute\n workItem = item\n DispatchQueue.main.asyncAfter(deadline: .now() + 3.0, execute: item)\n }\n \n func cancelDelayedAction() {\n workItem?.cancel()\n workItem = nil\n print("Task cancelled")\n }\n \n func doSomething() {\n // Your code\n }\n}\n\n// Usage\nlet task = DelayedTask()\ntask.scheduleDelayedAction()\n// Cancel after 1 second\nDispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {\n task.cancelDelayedAction()\n}\n\nNote the [weak self] — this is mandatory to avoid memory leaks in Swift. The delay can outlive the controller if you don't weaken the reference.
3. Timer.scheduledTimer: Delay with Repetition
\nSwift timers are not just for repeating tasks. You can create a one-shot timer with a delay. Plus: the timer is easy to cancel and can be paused.
\n\nclass TimerExample {\n var timer: Timer?\n \n func startDelayedAction() {\n // One-shot timer after 1.5 seconds\n timer = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: false) { [weak self] _ in\n print("Timer fired after 1.5 sec")\n self?.updateUI()\n }\n }\n \n func stopTimer() {\n timer?.invalidate()\n timer = nil\n }\n \n func updateUI() {\n // Update the interface\n }\n}\n\nWhen to use Timer
\n- \n