Swift Concurrency - non-blocking sleep?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
In Swift concurrency, the non-blocking way to pause work is Task.sleep. It suspends the current async task without blocking the underlying thread, which is exactly what you want in structured concurrency. Thread.sleep, by contrast, blocks a real thread and should not be your default in async code.
What Non-Blocking Sleep Means
A blocking sleep occupies the thread for the whole delay. A non-blocking sleep suspends the task and lets the executor run other work.
That distinction matters because async functions are designed to cooperate with the runtime scheduler. If you block the thread, you reduce concurrency and can make the app feel less responsive.
Use Task.sleep in Async Code
Modern Swift gives you this pattern:
Older forms use nanoseconds directly:
The duration-based form is usually easier to read.
Cancellation Matters
Task.sleep is cancellable. If the task is canceled while sleeping, the call throws. That is a feature, not a nuisance, because sleeping work should usually stop if the task itself is no longer needed.
If cancellation should propagate, do not ignore the error silently.
When Thread.sleep Is Still Wrong
You may still see code like this:
That is fine only in old synchronous code where blocking is intentional and harmless. Inside async workflows, it defeats the point of Swift concurrency.
Use Task.sleep in:
- retry backoff logic
- debouncing async tasks
- test helpers in async code
- temporary pacing of background work
A Practical Retry Example
Non-blocking sleep is especially useful in retry logic.
This pauses between attempts without tying up a thread. The same principle applies to small orchestration delays, but if your code is waiting for a real event, an async callback or sequence is usually better than sleeping and polling.
Another practical point is testability. A sleep-based delay can be acceptable in small examples, but production workflows often benefit from injecting a clock or delay abstraction so long waits are not hard-coded into tests. That keeps async code fast to test and easier to reason about. This matters most in retry-heavy code, where several real waits can make the test suite unnecessarily slow. It is a small design choice, but it keeps concurrency code maintainable as the workflow grows.
Common Pitfalls
The biggest mistake is using Thread.sleep inside async code and assuming it is equivalent. It is not.
Another mistake is forgetting that Task.sleep can throw when the task is canceled. If cancellation matters, handle that path intentionally.
A third mistake is using sleep where a real synchronization primitive, timer, or event-driven callback would be better. Sleep is for delay, not for correctness.
Summary
- In Swift concurrency, use
Task.sleepfor non-blocking delays. - '
Task.sleepsuspends the task instead of blocking the underlying thread.' - Prefer the duration-based form when available because it is easier to read.
- Expect cancellation and handle the thrown error appropriately.
- Avoid
Thread.sleepin async code unless you intentionally want to block a real thread.
Related reading
- Swift how to wrap completion into an async/await?
- Swift Images change to wrong images while scrolling after async image loading to a UITableViewCell
- Switching threads within PDB
- Sync data between Android App and webserver
- Swift Convert enum value to String?
- swift convert RangeInt to Int
- Sync in Android sqlite and sql server crud operation in two ways
- Synchronisation algorithms
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.