Tech News
← Back to articles

Fucking Approachable Swift Concurrency

read original related products more articles

So far we've talked about when code runs (async/await) and how to organize it (Tasks). Now: where does it run, and how do we keep it safe?

Most apps just wait Most app code is I/O-bound. You fetch data from a network, await a response, decode it, and display it. If you have multiple I/O operations to coordinate, you resort to tasks and task groups. The actual CPU work is minimal. The main thread can handle this fine because await suspends without blocking. But sooner or later, you'll have CPU-bound work: parsing a giant JSON file, processing images, running complex calculations. This work doesn't wait for anything external. It just needs CPU cycles. If you run it on the main thread, your UI freezes. This is where "where does code run" actually matters.

The Old World: Many Options, No Safety

Before Swift's concurrency system, you had several ways to manage execution:

Approach What it does Tradeoffs Thread Direct thread control Low-level, error-prone, rarely needed GCD Dispatch queues with closures Simple but no cancellation, easy to cause thread explosion OperationQueue Task dependencies, cancellation, KVO More control but verbose and heavyweight Combine Reactive streams Great for event streams, steep learning curve

All of these worked, but safety was entirely on you. The compiler couldn't help if you forgot to dispatch to main, or if two queues accessed the same data simultaneously.

The Problem: Data Races

A data race happens when two threads access the same memory at the same time, and at least one is writing:

var count = 0 DispatchQueue . global ( ) . async { count += 1 } DispatchQueue . global ( ) . async { count += 1 }

Data races are undefined behavior. They can crash, corrupt memory, or silently produce wrong results. Your app works fine in testing, then crashes randomly in production. Traditional tools like locks and semaphores help, but they're manual and error-prone.

... continue reading