Mobile system design · 17 min
Mobile system design interview: how the round is scored
How a mobile system design round runs, the seven things a senior answer covers, a worked offline sync example, and how Senior and Staff are scored.
Mobile system design · 15 min read
What an iOS design round adds: background limits, background URLSession, storage, image pipelines and push, with a worked photo feed design.
The general shape of a mobile design round is covered in Mobile system design interview: requirements, source of truth, API, caching, sync, lifecycle, observability. This guide is about what an iOS interviewer adds on top. The architecture can be sound and still lose the round if it promises something iOS does not allow, or misses a tool iOS gives you for free.
The same five places, in almost every iOS design round I have run:
| Area | The common wrong answer | What iOS does |
|---|---|---|
| Background work | “We sync every 15 minutes in the background” | BGTaskScheduler lets you ask; the system decides when, based on usage, battery and network |
| Uploads | “Upload in a background thread” | Once suspended, the app executes nothing; a background URLSession lets the OS carry on the upload for you |
| Memory | “Cache all images in memory” | The app is terminated under memory pressure; large decoded images are the usual cause |
| Push | “Push the new data to the app” | A visible notification is shown by the system; silent pushes are throttled and not guaranteed |
| Storage | “Save it in UserDefaults” | UserDefaults is for small preferences; records belong in a database, secrets in the Keychain |
An answer that avoids all five is already above most. The rest of this guide is the detail behind each.
An iOS app in the background is suspended shortly after the user leaves it, and may be terminated later without being told. The tools for doing work anyway:
BGAppRefreshTask: a short window to refresh content. You schedule a request with an earliest start date; the system picks the actual time. Apps the user opens often get more opportunities.BGProcessingTask: longer work, can require external power and network. Useful for maintenance such as database cleanup or index rebuilds.URLSession: uploads and downloads that the system carries out while your app is suspended or not running, then relaunches your app to deliver the result. The right answer for any large or important transfer.content-available: can wake the app briefly, but delivery is throttled and not guaranteed. A design must never depend on it.The senior sentence is: “The design works if none of these ever run, and gets better when they do.” Foreground sync on launch is the guarantee; background work is an optimisation.
Two details under that sentence come up in deep dives. First, a BGProcessingTask gets an expirationHandler, and when it fires you have very little time: write a checkpoint you can resume from and call setTaskCompleted(success: false). Ignore it and the task is killed regardless, and it counts as an overrun, which makes the system schedule you later next time. Second, that task is not where the download happens. It wakes the app, checks what finished and queues what did not. The bytes go through a background URLSession, which the system keeps running after the app is suspended or even terminated, and which relaunches the app in the background once a transfer completes.
“Where would you store it?” comes up in every iOS design round. The answer depends on what “it” is.
| Data | Store | Why |
|---|---|---|
| User preferences, small flags | UserDefaults |
Small, simple, read at launch |
| Tokens, passwords, keys | Keychain | Encrypted, survives reinstall depending on configuration, access control available |
| Structured records the UI queries | SQLite via Core Data, SwiftData or GRDB | Queries, relationships, migrations, change observation |
| Large files: images, video, documents | Files in Caches or Application Support | Caches can be purged by the system; Application Support cannot |
| Data shared with an extension | App Group container | The only shared location between app and extension |
The Caches versus Application Support line catches people. A downloaded photo the user can fetch again belongs in Caches. A photo the user took offline and has not uploaded belongs in Application Support, because losing it is data loss.
Prompt: “Design the iOS client for a photo-sharing feed. Users scroll a feed and can post photos, including when offline.”
Feed freshness (a pull to refresh is enough, or live updates?), expected image sizes, whether posts can be edited, and how long an offline post may wait. Then state scope: no stories, no video in version one.
UICollectionViewDataSourcePrefetching or the SwiftUI equivalent starts fetches for upcoming rows and cancels them when the user scrolls away.pending to the database. The feed shows it immediately with a “posting” state.URLSession upload task from the file. It survives the app being suspended or terminated.posted with the server id, or failed with a retry count.pending record without a live transfer is resubmitted. The server accepts an idempotency key per post, so a retried upload never creates a duplicate.The idempotency key is the detail interviewers wait for. Without it, “retry on failure” means “sometimes post twice”.
A visible notification for new likes and comments is shown by the system without waking the app. A Notification Service Extension can download an image and attach it to the notification before it is shown. Silent pushes may be used to hint that new content exists, never to deliver it reliably.
Upload success rate and time to success, count of pending posts older than a day (a stuck queue), memory warnings and terminations by device class (MetricKit reports these), and feed load time from launch.
These are iOS system design interview questions as they are usually posed, with the platform detail each one is really testing. The product changes from loop to loop; the iOS detail underneath does not.
| Prompt | The iOS detail it tests | The answer that scores |
|---|---|---|
| “Design a photo feed with offline posting.” | Background URLSession, Caches versus Application Support |
The system carries the upload while the app is suspended; the unsent photo lives where iOS will not purge it |
| “Design a messaging client.” | What push can deliver and what it cannot | A visible notification shows without waking the app; silent pushes are throttled, so history catches up on launch |
| “Design a podcast or video app with downloads.” | Background downloads and storage limits | Background session downloads, files marked for the right backup behaviour, space checked before a large download |
| “Design a widget or a Live Activity for this app.” | Extensions run in a separate process with tight limits | Shared data through an App Group container; the extension reads a snapshot, it does not fetch the world |
| “Design sign-in and session handling.” | Where secrets live | Tokens in the Keychain with an accessibility class chosen on purpose; a refresh that runs once for concurrent callers |
| “Design a feed that stays smooth on a three-year-old iPhone.” | Memory and decoding, not the network | Downsample with ImageIO, decode off the main thread, a cost-limited cache, purge on memory warning |
Each of these can be answered with the platform details earlier on this page. The one that decides many iOS rounds is background execution: say what iOS allows, and design so the app is correct even if no background time is ever granted.
| Follow-up | What it tests | A strong answer |
|---|---|---|
| “The user kills the app during an upload.” | Background session knowledge | The system continues the transfer; the app reconciles on relaunch |
| “The download resumes after the app was killed.” | Resumable state | Bytes written are recorded only once they are on disk; resume with a Range request and If-Range on the ETag, so a file changed on the server restarts instead of being spliced |
| “The signed URL expired while the task waited for the system.” | Scheduling versus authorisation | The queued item keeps a reference to credentials; a fresh URL is minted when the work runs |
| “Memory warnings on older iPhones.” | Image pipeline depth | Cost-limited cache, downsampling, purge on warning |
| “The feed must update live.” | Freshness trade-offs | WebSocket in foreground, polling as fallback, push as a hint |
| “Add a share extension.” | Extension constraints | App Group container, lower memory limit, handing work to the app |
| “Support 5 million users.” | Whether you drift to backend | Client stays the same; mention server concerns briefly and return |
A Senior answer gets the above right. A Staff answer also covers how this client fits the rest of the app and the organisation: a shared image pipeline other features use instead of three separate ones, the API contract negotiated with backend (cursor format, idempotency keys, error codes), a rollout plan with a flag on the new upload path, and the metric that would trigger a rollback. How the Staff call is made in the debrief is in the Staff mobile system design interview.

Mobile system design · 17 min
How a mobile system design round runs, the seven things a senior answer covers, a worked offline sync example, and how Senior and Staff are scored.

iOS · 16 min
Twelve senior iOS interview questions for 2026: what each scores, a weak and a senior answer, and the follow-up on Swift 6 concurrency, SwiftUI, architecture.

iOS · 14 min
Ten iOS architecture interview questions and how senior answers are scored: MVVM, TCA, navigation, dependency injection, SPM modules, testing.