iOS System Design
iOS system design is about designing modules and libraries, not algorithms. The interviewer gives an open task ("design a screen", "design an analytics library") and watches how you break it into layers: where data comes from, what happens when the connection drops, how different threads work with shared state safely, and how easily the module extends to new requirements.
The traps here are architectural, not syntactic. Keeping responses only in memory loses them on a crash. Ingesting events from any thread without synchronization invites data races. Updating the UI off the main queue causes unpredictable failures. Hard-coding one backend and a fixed set of screens breaks the module on the first change. The layers below cover the four pillars from which almost any answer is assembled.
Topic map
- Networking via URLSession — asynchronous data loading via data tasks and the data/response/error model.
- Offline cache — persisting successful responses to disk and serving them when a request fails.
- GCD queues — serial and concurrent dispatch queues and the "UI on the main queue only" rule.
- Thread safety — guarding shared mutable state with a serial queue or a barrier instead of races.
- Backend-driven UI — a screen whose composition is described by the backend response, for extensibility without a release.
Common traps
| Mistake | Consequence |
|---|---|
| Keeping data only in memory | A crash or app eviction loses everything unsaved |
| Ingesting/mutating shared state from any thread without synchronization | Data races and elusive crashes |
| Updating the UI off a background queue | Unpredictable rendering failures and crashes |
| Assuming offline works by itself | iOS does not replay requests for you — the cache is built by hand |
| Hard-coding one backend and a fixed set of screens | Any API or tab-set change requires a release |
Thinking URLSession blocks the calling thread | Wrong model — tasks run asynchronously |
Interview relevance
System design is asked to separate someone who "codes to a guide" from someone who makes engineering decisions under constraints. A strong candidate names the risks themselves — "what about a dropped connection?", "which thread mutates this?" — and closes them with layers: persistence, synchronization, the main queue for UI, pluggable abstractions.
Typical checks:
- How loading via
URLSessionworks and why it is asynchronous. - How to survive offline and not lose data on a crash (disk, not just memory).
- The difference between a serial and a concurrent queue, and where the main thread is mandatory.
- How to guard shared state from races and keep the module extensible.
Common wrong answer: "I'll store everything in an in-memory array and update the UI straight from the network callback". In fact such a module loses data on a crash, races when accessed from different threads, and crashes when updating the UI off the main queue.