dispatch_after in Swift: GCD Under the Hood — Analysis with Examples

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

dispatch_after in Swift: How GCD Executes Delayed Tasks Under the Hood



Imagine: you're writing an app in Swift, and you need to execute a piece of code not immediately, but, say, after 3 seconds. The first thing that comes to mind is dispatch_after. But if you look into older versions of Swift or on Stack Overflow, you'll see that this method has changed. And most importantly, few people understand what actually happens inside Grand Central Dispatch (GCD) when we say: "Do this in 2 seconds."



In this article, we won't just show how to write dispatch_after in modern Swift. We'll dig under the hood of GCD, break down queues, threads, and timers, so you can write reliable and efficient asynchronous code. Let's go!



What is dispatch_after and why did it become asyncAfter?



In older versions of Swift (1.x, 2.x), you might have encountered code like this:



dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) {    print("2 seconds have passed")}


This code worked, but it looked cumbersome. Starting with Swift 3, Apple refactored the entire GCD API, making it more "Swifty." Now the same functionality looks like this:



DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {    print("2 seconds have passed")}


Note: asyncAfter is a method of the queue (DispatchQueue), not a separate function. This is a key change: now you explicitly specify on which queue to execute the task.



How GCD Works Under the Hood: Queues, Threads, and Timers



To understand dispatch_after (or asyncAfter), you need to understand three entities:



  • DispatchQueue — a task queue. It can be serial or concurrent.
  • DispatchWorkItem — the task you put in the queue. In our case, it's a closure.
  • DispatchTime — the point in time when the task should start. GCD uses a system timer to track deadlines.


When you call asyncAfter, GCD does not create a new thread. Instead, it:



  1. Creates a timer that will fire at the specified time.
  2. Places the task in a special queue for delayed tasks (often called a dispatch timer).
  3. When the timer fires, GCD moves the task to the regular DispatchQueue, where it waits for its thread.


If the queue you are putting the task into is busy with other tasks, your delayed task may execute later than the specified deadline. This is an important point: dispatch_after guarantees that the task will not execute before the deadline, but it may execute later.



Practical Example: dispatch_after for UI Updates



The most common scenario is updating the interface some time after a user action. Let's say you show a "Saved" message and hide it after 2 seconds:



func showTemporaryMessage() {    let messageLabel = UILabel()    messageLabel.text = "Saved!"    messageLabel.alpha = 1.0    view.addSubview(messageLabel)

DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { UIView.animate(withDuration: 0.5) { messageLabel.alpha = 0.0 } completion: { _ in messageLabel.removeFromSuperview() } }}


Note: we use DispatchQueue.main because all UI operations must be performed on the main thread. If we called asyncAfter on a background queue and then tried to modify the UI, the app would crash.



Pitfalls of dispatch_after: Memory Leaks and Capturing self



One of the most common mistakes is a strong reference to self in

Blogs

Book Recommendations