Build a Paging Card Carousel in UIKit with Dataset Switching and Auto-Scroll
Company: Robinhood
Role: iOS Engineer
Category: Software Engineering Fundamentals
Difficulty: easy
Interview Round: Onsite
In an iOS coding round you build a small app from scratch in Xcode. The interviewer first shows a demo of a horizontally swipeable card carousel; you reproduce it, then extend it in a follow-up. A card is described by this model:
```swift
struct CardItem {
let color: UIColor
let title: String
let subtitle: String
}
```
Build the app to the following specification, which follows the reported implementation:
- Each card is a rounded rectangle filled with the item's color, with a bold title above a smaller subtitle in its bottom-left corner, both in white.
- Swiping moves exactly one card at a time and snaps so that one card fills the carousel, with a visible gap between neighboring cards.
- The carousel is a reusable component that the host screen treats as a black box: the host embeds it, gives it a frame and passes it an array of `CardItem` values, and nothing else.
- The host screen shows the carousel full width, 200 points tall and centered vertically, with three buttons at the bottom. Each button loads one of three hardcoded datasets (for example Red, Green and Blue; Orange and Purple; Teal, Pink, Indigo and Brown), and loading a dataset returns the carousel to its first card.
- The reported version used a 16-point corner radius, a 16-point inset on each side of a card and 16 points of text padding; treat these as defaults unless the demo shows otherwise.
### Clarifying Questions
- UIKit or SwiftUI, and is a code-only layout fine or is a storyboard expected?
- Which iOS versions must the app support, since that decides which layout and paging APIs are available?
- Should manual swiping wrap around at the ends, or only automatic paging?
- If the user swipes while automatic paging is on, should the 2-second count start over?
### Part 1 — Card cell and paging carousel
Build the card cell and a reusable carousel view controller that displays an array of `CardItem` values as horizontally paging cards and exposes one method for replacing its items.
```hint Make the pages line up
Paging stops at multiples of the scroll view's width. Decide how wide each page must be, and where the visible gap between cards can then come from.
```
#### What This Part Should Cover
- The choice of container (collection view, plain scroll view or page view controller) and cell reuse
- How page width, item spacing and the visible gap interact with paging
- Keeping the layout and the current card correct when the carousel's size changes
### Part 2 — Host screen with dataset switching
Build the host screen: embed the carousel, lay out the carousel and the three buttons, and make each button replace the carousel's cards with its dataset, starting again from the first card.
```hint Embed it properly
Think about which calls make a child view controller receive its lifecycle and layout callbacks, and what the carousel would show if you were on the fourth card and loaded a two-card dataset.
```
#### What This Part Should Cover
- View controller containment and where layout code runs
- Layout relative to the safe area
- Replacing the data and resetting the scroll position without stale or empty pages
### Part 3 — Follow-up: automatic paging
Add a switch to the host screen. While it is on, the carousel advances one card every 2 seconds and returns to the first card after the last. Loading a new dataset while it is on restarts the 2-second count from the first card, and automatic paging stops while the screen is not visible.
```hint Follow the references
Trace who holds whom among the run loop, the timer, its closure and the carousel, and decide at which moments the timer must be created and destroyed.
```
#### What This Part Should Cover
- Timer lifecycle: starting, stopping and restarting without duplicate timers
- Memory: retain cycles and invalidation
- Edge cases: zero or one card, the user swiping while automatic paging is on, leaving the screen
### What a Strong Answer Covers
- A runnable app built in small steps and checked on the simulator after each one
- A clean split into the model, the cell, a carousel with a small public API, and the host screen
- Correct paging geometry, including after rotation or other size changes
- Correct timer and memory management, with the follow-up added without reworking the carousel
- Explicit handling of empty, single-card and dataset-switch cases
- Clear reasoning about the UIKit lifecycle methods used for layout, appearance and disappearance
### Follow-up Questions
- How would you make manual swiping loop seamlessly in both directions, so that the first card follows the last?
- How would you show a slice of the previous and next cards at the edges while keeping one-card snapping?
- How would you unit test automatic paging without waiting for real seconds to pass?
- How should the carousel behave for users who turn on Reduce Motion or VoiceOver?
Overview: An iOS coding exercise: build from scratch in UIKit a reusable, horizontally paging card carousel, a host screen whose three buttons swap between hardcoded datasets, and a switch that advances the cards every two seconds. It tests collection view paging geometry, child view controller containment, and timer lifecycle and memory management.
Read the full Robinhood iOS Engineer interview experience this question came from