Queues and Background Tasks in Swift: Writing Code That Doesn't Lag

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

Queues and Background Tasks in Swift: How to Make Your App Fly

\n\n

Imagine: you open a pizza ordering app, tap "View Menu," and the screen freezes for five seconds. You start getting nervous, the pizza seems unappetizing, and the app goes in the trash. Sound familiar? If you're a Swift developer, you've likely encountered situations where the interface "lags" due to heavy operations — loading images, parsing JSON, or complex calculations. The secret to a smooth UX lies in properly working with queues and background tasks.

\n\n

In this article, we'll explore how to organize multithreading in Swift: from classic GCD and OperationQueue to modern async/await. You'll learn how to offload heavy work from the main thread, avoid deadlocks, and write code that runs fast and predictably. Let's go!

\n\n

Why a Queue Isn't About Boredom at the Store

\n\n

In Swift, a queue is not where you stand with a shopping cart. Queues (DispatchQueue) are a mechanism for managing tasks. Imagine you have several chefs (threads). One chef serves the dining room (main thread — UI), while the others cook in the kitchen (background threads). If you make the waiter fry a steak, the dining room stops. The same goes for the interface: all UI updates must happen only on the main thread, and everything else in the background.

\n\n

In Swift, there are two types of queues:

\n
    \n
  • Serial — tasks execute one after another. Ideal for protecting shared resources.
  • \n
  • Concurrent — tasks start simultaneously. Great for loading images or parallel computations.
  • \n
\n\n

The system itself manages the thread pool, so you don't need to create them manually. You just say: "Do this in the background, then return the result to the main thread." And Swift does it elegantly.

\n\n

GCD (Grand Central Dispatch) — An Old Friend Is Better Than Two New Ones

\n\n

Grand Central Dispatch is a low-level API that appeared back in Objective-C. It's alive and well, and every Swift developer should know it. The main work happens through DispatchQueue.

\n\n

Here's the simplest example — loading data in the background and updating the UI:

\n\n
import UIKit\n\nclass ViewController: UIViewController {\n    @IBOutlet weak var imageView: UIImageView!\n    \n    override func viewDidLoad() {\n        super.viewDidLoad()\n        loadImage()\n    }\n    \n    func loadImage() {\n        // Go to a background queue\n        DispatchQueue.global(qos: .background).async {\n            // Heavy work: loading an image\n            guard let url = URL(string: "https://example.com/pizza.jpg"),\n                  let data = try? Data(contentsOf: url),\n                  let image = UIImage(data: data) else {\n                return\n            }\n            \n            // Return to the main thread to update the UI\n            DispatchQueue.main.async {\n                self.imageView.image = image\n            }\n        }\n    }\n}\n
\n\n

Notice the qos (Quality of Service). This is the task's priority: .userInteractive — for animations, .background — for synchronization, .utility — for progress indicators. Choosing the right QoS helps the system allocate resources.

\n\n

DispatchGroup: Wait for Everyone, Not Just One

\n\n

Imagine you need to load three images and only then display them. Without DispatchGroup, you would start three asynchronous requests and not know when all of them finish. The solution is a group:

\n\n
func loadMultipleImages() {\n    let group = DispatchGroup()\n    var images: [UIImage] = []\n    \n    let urls = ["url1", "url2", "url3"]\n    \n    for urlString in urls {\n        group.enter() // Enter the group\n        DispatchQueue.global().async {\n            // Loading                

Blogs

Book Recommendations