-
Notifications
You must be signed in to change notification settings - Fork 0
21 — Common GCD Gotchas
A rundown of classic kitchen mistakes: a waiter who forgets to tell the head chef the dish is ready (forgetting to hop back to the main queue), a chef who keeps holding onto a ticket for a customer who already left (retain cycles), and a rush-order chef getting stuck behind a slow prep chef who's holding the one shared knife (priority inversion).
Three concrete gotchas:
-
Retain cycles — capturing
selfstrongly in a closure that outlives it, fixed with[weak self]. -
Forgetting to hop back to main — background work that mutates UI without dispatching back to
DispatchQueue.main, causing updates off the main thread. - Priority inversion — low-QoS work holding a shared lock blocks high-QoS work waiting on that same lock, effectively dragging the high-QoS work down to low priority.
1) Retain cycle: self ──strong──▶ closure ──strong──▶ self (never released)
2) Forgotten hop: background work ──▶ label.text = x (off main thread!)
3) Priority inversion: [high-QoS] waits ──▶ [low-QoS holds lock] ──▶ (blocked)
// Gotcha 1: retain cycle
queue.async { [weak self] in
self?.doWork()
}
// Gotcha 2: forgetting to hop back to main
queue.async {
let result = compute()
DispatchQueue.main.async {
self.label.text = result // UI updates must happen here
}
}@MainActor eliminates gotcha 2 at compile time (you can't accidentally touch UI off the main actor), and structured concurrency's automatic cleanup reduces (but doesn't eliminate) gotcha 1's surface area — priority inversion (gotcha 3) can still happen with actors, though the scheduler manages it differently.
Most GCD bugs are one forgotten hop, one forgotten [weak self], or one shared bottleneck.
Real kitchen mistakes get noticed immediately by a human; these three gotchas often produce silent, intermittent bugs that only show up under specific timing conditions.
A closure captures self strongly, is stored as a long-lived property on self, and is never called again after being set — which of the three gotchas above is this, and why does it leak?