AceMobileInterview

Interview guides / ios

iOS System Design Interview Questions

iOS system design interview questions covering feed clients, chat, offline sync, caching, and tradeoffs with example answer frameworks.

iOS system design interviews are client-first. Interviewers care about architecture boundaries, networking, caching, offline behavior, performance on device, and explicit tradeoffs.

Do not design only the backend. Talk about MVVM or similar boundaries, repositories, image pipelines, outbox sync, and what breaks on flaky networks.

AceMobileInterview includes full mobile system design prompts with diagrams and tradeoff writeups.

  1. 1.Design an Instagram-lite iOS client: feed, upload, likes, comments, profile, and push. What are the main components?

    Use feature modules (Feed, Upload, Profile) with MVVM. Views render state; ViewModels own UI state and call repositories. Local DB caches recent posts; image pipeline uses memory + disk cache. Likes go through an outbox for optimistic UI. Uploads use a dedicated UploadManager (actor or serial queue). Push invalidates and triggers lightweight sync. Call out offline banners, idempotent mutations, and tradeoffs like optimistic vs pessimistic likes.

  2. 2.How would you design a realtime chat client for iOS?

    Treat local DB as source of truth, WebSocket as delivery optimization, and APNs for wakeups when disconnected. Sends go to an outbox first so offline works. RealtimeClient owns reconnect/backoff. After reconnect, catch up with events-since-cursor. Discuss at-least-once delivery plus idempotent client message IDs.

  3. 3.How do you design feature flags / remote config safely on iOS?

    Cached-first launch with typed keys, in-binary defaults, and non-blocking fetch. Kill switches must work offline from last-known-good. Avoid blocking startup on network. Atomic snapshot swap for readers. Prefer coarse flags early; add fine-grained flags only with hygiene.

  4. 4.Design a photo-sharing iOS client: home feed, upload, likes, comments, profile, and push. Give a thorough client design with architecture, diagram-level components, networking, caching, offline, performance, and explicit tradeoffs.

    ## Overview Treat this as a modular iOS client with a local cache, optimistic engagement, resumable uploads, and clear offline degradation—not a backend-only whiteboard. Interviewers want to hear how MVVM boundaries, repositories, and sync interact under real device constraints (memory, battery, flaky networks). ## Architecture diagram ```mermaid flowchart TB subgraph UI["UI layer"] FeedView["FeedView<br/>SwiftUI/UIKit"] UploadView["Upload Composer"] ProfileView["ProfileView"] end subgraph VM["Presentation"] FeedVM["FeedViewModel"] UploadVM["UploadViewModel"] ProfileVM["ProfileViewModel"] end subgraph Domain["Domain / Data"] FeedRepo["FeedRepository"] EngageRepo["EngagementRepository"] UploadMgr["UploadManager actor"] Outbox["Outbox queue"] LocalDB[(SwiftData / Core Data)] ImageCache["Image cache<br/>NSCache + disk"] end subgraph Remote["Remote"] API["REST API"] CDN["Media CDN"] APNs["APNs"] end FeedView --> FeedVM --> FeedRepo UploadView --> UploadVM --> UploadMgr ProfileView --> ProfileVM --> FeedRepo FeedRepo --> LocalDB FeedRepo --> API FeedRepo --> ImageCache ImageCache --> CDN EngageRepo --> Outbox --> API UploadMgr --> API UploadMgr --> LocalDB APNs -.-> FeedVM ``` ## Architecture Use MVVM with feature modules (Feed, Upload, Profile, Notifications). Views stay dumb: they render state and forward intents. ViewModels own UI state (loading/paging/errors/optimistic likes) and call repositories—never URLSession directly. Introduce a Coordinator/Router for profile deep links so features do not import each other. Shared AuthSession + APIClient are injected. UploadManager should be an actor (or serial operation queue) so concurrent composers cannot corrupt the job list. Keep analytics/haptics as side-effect services invoked from ViewModels after state transitions. ## Networking Cursor-paginated feed GET; ETag/If-None-Match on refresh; idempotent like/unlike POST with client-generated keys; comments paginated separately. Media uses server-signed upload URLs (PUT) then a finalize call. APIClient: auth interceptor, single-flight token refresh, decode DTOs → domain models off the main actor. Prefetch next page when the user is ~5 items from the end. Background URLSession for large uploads that must survive app backgrounding. Cancel in-flight detail fetches when leaving a screen. Push (APNs) invalidates feed/inbox and triggers a lightweight sync—not a full refetch storm. ## Storage & caching Local DB is the cache/SoT for recently seen posts, profiles, and draft uploads. Image pipeline: memory NSCache + disk LRU with max bytes; decode at display size via ImageIO. Persist outbox rows for likes/comments. Evict old feed pages aggressively; pin “saved” posts longer. Never store access tokens in UserDefaults—Keychain only. Draft media stays on disk until server ACK, then delete or keep based on product policy. ## Offline mode Show last cached feed with an explicit stale banner and last-updated time. Likes/comments enqueue to outbox and show pending/failed affordances; flush on reconnect (NWPathMonitor). Uploads created offline remain drafts until network returns. Disable network-only surfaces (Explore/Discover) rather than faking freshness. On conflict (like count mismatch), server wins after reconciliation—roll back optimistic UI calmly. ## Performance Stable cell identities; downsample images before assign; prefetch URLs for upcoming cells; avoid main-thread image decode. Prefer diffable data sources / LazyVStack with explicit ids. Compress HEIC/JPEG before upload. Instruments: Time Profiler, Allocations, Hitches, Network. Bound concurrent decodes. Paginate comments; don’t load full comment trees into the feed cell model. ## Tradeoffs ### Optimistic likes vs server-confirmed likes **Option A — Optimistic UI:** Flip heart immediately, enqueue mutation, rollback on failure. Feels instant; requires conflict/rollback UX and careful idempotency. **Option B — Pessimistic UI:** Wait for 200 before updating. Simpler consistency; feels laggy on poor networks and trains users to tap repeatedly. **Pick A when:** Engagement is high-frequency and failures are rare/recoverable. **Pick B when:** Compliance/audit flows or when double-charges/side effects make rollback unsafe. ### Local DB as cache vs view-memory only **Option A — Persisted feed cache:** Survives process death; enables offline reading; more migration/complexity. **Option B — In-memory only:** Simple and fresh, but blank states after kills and no offline story. **Pick A when:** Offline/read-later matters and cold start UX matters. **Pick B when:** MVP throwaway prototype or highly personalized feed that is meaningless when stale. ### Background uploads vs foreground-only **Option A — Background URLSession:** Uploads continue when backgrounded; more setup (delegates, rejoin sessions) and edge cases. **Option B — Foreground only:** Easier reasoning; large uploads fail if user leaves. **Pick A when:** Media is core and uploads are multi-MB. **Pick B when:** Small images and sessions are short.

  5. 5.Design a feature-flag / remote-config system for a large iOS app: staged rollouts, kill switches, experimentation, and safe startup.

    ## Overview Flags must be cached-first, typed, and non-blocking at launch, with kill switches that can disable broken features without an App Store release. ## Architecture diagram ```mermaid flowchart TB App[App launch] --> Cache[Disk flag snapshot] Cache --> Snapshot[In-memory snapshot] Snapshot --> VM[Feature ViewModels] App --> Fetch[Remote Config fetch] Fetch -->|update| Snapshot Fetch -->|persist| Cache Push[Silent push] --> Fetch Defaults[Compiled defaults] --> Snapshot ``` ## Architecture FeatureFlagProvider protocol with typed keys. ViewModels depend on the provider—not NotificationCenter blasts. Experiment assignment sits beside flags. Bootstrap defaults ship in-binary for first install. ## Networking Non-blocking fetch on launch + periodic refresh + optional silent push. Short timeout; CDN JSON/protobuf; schema version field. Analytics exposures batched. ## Storage & caching Last-known-good on disk; schema migrations; unknown keys ignored; defaults always defined. ## Offline mode Offline uses cache/defaults forever; never crash on missing key; queue exposures. ## Performance O(1) dictionary reads; parse off main; atomic snapshot swap on MainActor if UI observes. ## Tradeoffs ### Cached-first vs network-first launch **Option A — Cached-first:** Instant startup using last snapshot; may be briefly stale. **Option B — Network-first:** Freshest flags; slows/blocks launch and fails offline. **Pick A when:** Consumer apps where launch time matters. **Pick B when:** Rare safety-critical configs that must be fresh (still prefer timeout+cache fallback). ### Client percentage rollout vs server targeting **Option A — Client hash of userId:** Works offline; simple; weaker abuse control. **Option B — Server decides:** Central control and richer targeting; requires network. **Pick A when:** Sticky offline experiments. **Pick B when:** Regulated targeting or rapid kill that must be server authoritative. ### Many fine-grained flags vs coarse modules **Option A — Fine-grained:** Precise control; operational sprawl and interactions. **Option B — Coarse modules:** Fewer combinations; less flexibility. **Pick A when:** Mature platform with flag hygiene. **Pick B when:** Early product—prefer fewer flags.

  6. 6.Design a robust iOS networking layer: auth, refresh, retries, errors, caching, testability.

    ## Overview A single APIClient with interceptor pipeline and protocol boundaries keeps features testable and consistent. ## Architecture diagram ```mermaid flowchart TB VM --> Repo --> APIClient APIClient --> Auth[Auth Interceptor] APIClient --> Retry[Retry Policy] APIClient --> Session[URLSession] Auth --> Keychain Repo --> DTO[DTO mapper] ``` ## Architecture Features depend on repositories/protocols. APIClient handles auth header, redacted logs, refresh single-flight (actor). Map transport errors to domain errors for ViewModels. ## Networking One session config; refresh-on-401 once; retry idempotent GETs only by default; timeouts; optional pinning for high risk. ## Storage & caching Tokens Keychain; URLCache where safe; DTO≠domain; per-endpoint TTL policies. ## Offline mode NWPathMonitor fail-fast OfflineError; writes use feature outboxes—not generic HTTP magic. ## Performance Cancel on disappear; coalesce duplicate GETs; measure p95; HTTP/2. ## Tradeoffs ### Refresh strategy **Option A — Refresh on 401:** Lazy; can stampede without single-flight. **Option B — Proactive refresh:** Fewer mid-flight failures; more refresh traffic. **Pick A when:** With single-flight lock. **Pick B when:** Short-lived tokens with predictable expiry. ### Library vs URLSession **Option A — URLSession:** First-party, enough for most. **Option B — Alamofire/etc:** Faster extras; dependency cost. **Pick A when:** Default modern apps. **Pick B when:** Team already standardized on a lib.

Keep going with AceMobileInterview

Reading helps. Timed practice locks it in. Jump into the interactive track for algorithms with LeetCode links, studio projects, debugging zips, and mobile system design.

iOS trackAndroid trackMore guides