Irbisa · Cheatsheet
iOS System Design
The design round: feed, chat, live tracking, uploads, pagination, caching, idempotency, server-driven UI, analytics, super-apps
You have 45 to 60 minutes to design an iOS feature on a whiteboard. How do you split the time, and what is the interviewer actually grading?
REST, GraphQL or gRPC: which API style do you propose for the iOS client, and what does each one cost the app?
Why does offset pagination show duplicates and gaps in a feed that changes while the user scrolls, and what does a cursor fix?
-- Offset: "skip 40 rows". One post inserted at the top shifts every row down,-- so page 3 starts with the last post of page 2. A deleted post is skipped the same way.SELECT id, created_at FROM postsORDER BY created_at DESC, id DESCLIMIT 20 OFFSET 40;…Every screen must be "fresh", so the app sends forty requests on cold start. Which data do you cache, for how long, and where is stale data acceptable?
A banking home screen shows six widgets from six services and stays blank until the slowest answers. What do you change on the client and the backend?
enum Section: CaseIterable, Sendable { case accounts, cards, loans, savings, cashback, offers }enum SectionState: Sendable { case loading, loaded(SectionData), failed } @MainActor @Observablefinal class HomeModel { private(set) var sections: [Section: SectionState] = [:] // filled from the disk cache first…Find the bug: tap Like and then Unlike quickly on a weak network, and the heart stays filled while the server has the post unliked.
@MainActor final class PostCellModel { private(set) var post: Post private let api: any LikeAPI init(post: Post, api: any LikeAPI) { self.post = post; self.api = api } func likeTapped() { post.isLiked.toggle() // optimistic: the heart fills at once post.likeCount += post.isLiked ? 1 : -1 Task { do { try await api.toggleLike(postID: post.id) } catch { post.isLiked.toggle() // roll back post.likeCount += post.isLiked ? 1 : -1 } } }}A payment request times out and the user taps Pay again. How do the client and the API make sure the card is charged only once?
// The key names the payment, not the HTTP requeststruct PaymentIntent: Codable, Sendable { let key: UUID let orderID: String let amount: Decimal}…A flash sale should end at midnight, yet some users can still open it the next morning. Which clock does the app trust, and who enforces the end?
// The API sends absolute instants: { "serverTime": "...Z", "offers": [{ "endsAt": "...Z" }] }struct Offer: Decodable, Sendable { let id: String let endsAt: Date // an instant in UTC, never "until midnight"}…Design the feed of an Instagram-like app: data flow, pagination, prefetching, media, and getting the user back to the same post after a relaunch.
Design a stories viewer like Instagram's: what do you preload, how many video players do you keep alive, and what is the memory budget?
Design posting a marketplace listing with ten photos: compression, an upload queue, retries, and a draft that survives the app being killed.
Design a messenger client like Telegram: transport, message states, local storage, ordering, and what happens offline or in the background.
Design live courier tracking: how does the courier's location reach the customer's screen, and what changes once the app is in the background or the phone is locked?
How would you build the app's own analytics layer: batching events, keeping them offline, sampling, honouring consent and switching vendors without touching features?
When is server-driven UI worth it, and how does an old app version cope with a component it has never seen?
// { "type": "stories", "props": { ... },// "fallback": { "type": "banner", "props": { "title": "New: stories", "url": "app://stories" } } }indirect enum Component: Decodable, Sendable { case banner(Banner) case productGrid(ProductGrid) case unsupported(fallback: Component?) // a type this build has never seen…A dozen teams ship banking, taxi and food into one iOS super-app. How do you structure it so no team slows launch or another team's release?