iosNudge

System design interviews

Chapter 8 of 10 6 min read

In a mobile system design round you plan an app or a feature at a high level. There is no "correct" design. The interviewer wants to see how you think, how you structure the problem, and how you choose between options.

This chapter is a short overview. The separate iOS System Design Playbook covers each step in depth, with full worked designs.

What the round looks like

The interviewer gives a short, open prompt:

  • "Design a photo feed app, like Instagram."
  • "Design a chat app."
  • "Design offline support for a notes app."
  • "Design an image loading library."

You get 45–60 minutes. You draw boxes on a whiteboard or an online drawing tool, and you talk.

It is not a backend design round. You do not need to design databases with sharding. You focus on the app: its layers, data, networking, caching, offline and performance. You still talk about the API between the app and the server.

What interviewers look for

  • You ask questions first. You do not start drawing after 10 seconds.
  • You have a clear structure. The interviewer can follow you.
  • You go deep where it matters. Not 2 minutes on everything; 10 minutes on the hard parts.
  • You talk about trade-offs. "Option A is simpler, option B works offline. I pick B because…"
  • You know mobile limits. Bad networks, battery, memory, app killed in the background, small screens.

The framework

Use these 6 steps. Write them in the corner of the board so you do not forget one.

StepTime (45 min)What you do
1. Requirements5–7 minAsk questions. Agree on scope.
2. High-level architecture8–10 minDraw the main boxes and arrows.
3. Data model5 minShow the main Swift types.
4. API5 minList the server endpoints and the key protocols.
5. Deep dives15 minGo deep on 2–3 hard parts.
6. Trade-offs and wrap-up3–5 minSummarise choices and what you would do next.

Let us walk through it with one example: "Design a photo feed app."

Step 1: Requirements

Split them into three groups.

Functional (what it does):

  • Users see a feed of posts (photo, caption, author, likes).
  • The feed scrolls forever (pagination).
  • Users can like a post.

Non-functional (how well it does it):

  • Smooth scrolling (no dropped frames).
  • Works on slow networks.
  • Shows the last feed when offline.

Out of scope (say it out loud):

  • Uploading photos, comments, direct messages.

Good questions to ask:

  • "How many posts per page? Are images large?"
  • "Must the feed work offline, or just show cached data?"
  • "Should likes update in real time from other users?"
  • "Which iOS versions do we support?"

Step 2: High-level architecture

Draw the layers. Keep the arrows going one way.

+-------------------+        +----------------+
|     FeedView      +------->+  ImageLoader   |  memory + disk cache
+---------+---------+        +----------------+
          |
+---------v---------+
|   FeedViewModel   |  screen state, user actions
+---------+---------+
          |
+---------v---------+
|  FeedRepository   |  single source of data
+-----+-------+-----+
      |       |
+-----v---+ +-v------------+
|APIClient| |  FeedStore   |  local database (offline)
+---------+ +--------------+

Say what each part does in one sentence:

  • FeedView: shows posts, sends "load more" and "like" actions.
  • FeedViewModel: holds the screen state, calls the repository.
  • FeedRepository: the single source of data. It decides: cache, network, or both.
  • APIClient: HTTP requests and decoding.
  • FeedStore: saves posts on the device for offline use.
  • ImageLoader: downloads and caches images. The cells use it directly, so posts and images load separately.

Step 3: Data model

Show the main types in Swift. Keep them small.

struct Post: Identifiable, Codable, Sendable {
    let id: String
    let author: Author
    let imageURL: URL
    let caption: String
    var likeCount: Int
    var isLikedByMe: Bool
    let createdAt: Date
}

struct Author: Codable, Sendable {
    let id: String
    let name: String
    let avatarURL: URL
}

struct FeedPage: Codable, Sendable {
    let posts: [Post]
    let nextCursor: String?   // nil means no more pages
}

Step 4: API

List the endpoints and the key protocols.

GET  /feed?cursor=abc&limit=20   -> FeedPage
POST /posts/{id}/like
DELETE /posts/{id}/like
protocol FeedRepository: Sendable {
    func firstPage() async throws -> FeedPage
    func nextPage(after cursor: String) async throws -> FeedPage
    func setLiked(_ liked: Bool, postID: String) async throws
}

Mention why you use a cursor and not a page number: new posts at the top do not cause duplicates or skipped items.

Step 5: Deep dives

Pick 2–3 topics. Choose the ones that matter most for this app. Often the interviewer will pick one for you.

For a photo feed, good choices:

Image loading and caching

  • Two-level cache: memory (fast, small) and disk (slower, bigger).
  • Download images at the size you show, not the full size.
  • Cancel downloads for cells that scroll off screen.
  • Do not download the same URL twice at the same time.
actor ImageLoader {
    private var inFlight: [URL: Task<Data, Error>] = [:]

    func data(for url: URL) async throws -> Data {
        if let task = inFlight[url] {
            return try await task.value   // join the running download
        }
        let task = Task {
            try await URLSession.shared.data(from: url).0
        }
        inFlight[url] = task
        defer { inFlight[url] = nil }
        return try await task.value
    }
}

Pagination

  • Load the next page when the user is 5 items from the end.
  • Keep a flag so you never load the same page twice.
  • Stop when nextCursor is nil.

Offline

  • Save the first page to the local store.
  • On launch, show cached posts first, then refresh from the network.
  • Show a small "You are offline" banner instead of an error screen.

Optimistic likes

  • Update the UI at once when the user taps "like".
  • Send the request in the background.
  • If it fails, undo the change and show a short message.

Step 6: Trade-offs and wrap-up

End with a small table and one or two next steps.

ChoiceProsCons
Cursor paginationNo duplicates when new posts arriveCannot jump to page 10
Optimistic likesFeels instantMust undo on failure
SwiftData for offlineLess code, works well with SwiftUINeeds a newer iOS version; less control than raw SQLite
Own image loaderNo dependency, full controlMore code to maintain than a library

"If I had more time, I would add prefetching for images, and metrics for scroll performance and image load time."

Common mistakes

  • Starting to draw before asking questions. You may design the wrong thing.
  • Designing the backend. Keep the focus on the app.
  • Staying too shallow. Boxes and arrows are not enough. Go deep on at least two parts.
  • No trade-offs. Every choice has a cost. Say it.
  • Ignoring mobile problems. Bad network, app killed in the background, low memory, battery.
  • Not listening to hints. If the interviewer asks "What about offline?", it is a strong signal to go there.

Useful phrases

  • "Before I start, can I ask a few questions about scope?"
  • "I will keep uploads out of scope, unless you want me to include them."
  • "There are two options here. Let me compare them."
  • "Which part would you like me to go deeper on?"
  • "To summarise: the repository is the single source of truth, with a disk cache for offline."

Topics to know for this round

  • Layers: view, view model, repository, network, storage
  • Caching: memory, disk, HTTP cache, cache invalidation
  • Pagination: cursor vs offset
  • Offline: local storage, sync, conflict handling
  • Real-time: WebSockets, polling, push notifications
  • Concurrency: actors, cancellation, avoiding duplicate requests
  • Memory and performance: image sizes, cell reuse, main thread work
  • Errors and retries: backoff, user messages
  • Security: tokens in Keychain, HTTPS
  • Modularisation: feature modules with Swift packages

How to practise

  • Use the system design questions on this site. Try each one alone for 45 minutes, out loud, before you read the full design.
  • Draw on paper or in a simple drawing app. Practise drawing fast.
  • Read the iOS System Design Playbook for the full framework, more deep dives and complete example designs.
  • Practise with a friend. Ask them to interrupt you with "What about offline?" or "What if the image is 20 MB?"