Mobile system design · 15 min read

iOS system design interview: platform details that matter

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.

Where iOS answers usually break

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.

Background execution, precisely

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.
  • Background 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.
  • Remote notifications with 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.

Storage: a decision matrix

“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.

Worked example: a photo feed with offline upload

Prompt: “Design the iOS client for a photo-sharing feed. Users scroll a feed and can post photos, including when offline.”

Requirements worth asking about

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.

The feed

  • Source of truth: a local database of feed items (ids, metadata, image URLs, cursor). Screens observe it.
  • Paging: cursor-based from the server, because a feed changes while you scroll and offsets skip or repeat items.
  • Images: a pipeline of memory cache, disk cache, network. The memory cache is limited by cost, not count, since one full-size photo can be tens of megabytes decoded. Images are downsampled to the display size using ImageIO before decoding, and decoded off the main thread.
  • Prefetching: UICollectionViewDataSourcePrefetching or the SwiftUI equivalent starts fetches for upcoming rows and cancels them when the user scrolls away.

Posting offline

  1. The user picks a photo. The app copies a resized version into Application Support and writes a post record with status pending to the database. The feed shows it immediately with a “posting” state.
  2. An upload manager creates a background URLSession upload task from the file. It survives the app being suspended or terminated.
  3. When the system reports completion, the app updates the record to posted with the server id, or failed with a retry count.
  4. On next launch, any 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”.

Push

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.

Observability

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.

iOS system design interview questions

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-ups to expect

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

Senior and Staff

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.

Sources

Free guide: the Phoenix Method