Common iOS Questions
Swift Language Questions
Q: What is the difference between struct and class?
Structs are value types that are copied when assigned. Classes are reference types that share a reference. Structs are preferred for data models because they are thread-safe and do not have retain cycles. Classes are needed for inheritance and identity.
struct Point { var x: Int; var y: Int }
var a = Point(x: 1, y: 2)
var b = a // b is a copy
b.x = 10 // a.x is still 1
class Node { var value: Int; init(value: Int) { self.value = value } }
let x = Node(value: 1)
let y = x // y references the same object
y.value = 10 // x.value is also 10
Q: What is ARC and how does it work?
ARC (Automatic Reference Counting) tracks the number of strong references to each object. When the count reaches zero, the object is deallocated. Retain cycles occur when objects hold strong references to each other, preventing deallocation. Use weak or unowned references to break cycles.
Q: Explain the difference between weak and unowned.
Weak references do not increase the reference count and become nil when the object is deallocated. They must be Optional. Unowned references also do not increase the reference count but do not become nil. They crash if accessed after the object is deallocated.
UIKit vs SwiftUI
Q: When would you choose UIKit over SwiftUI?
- Complex custom layouts that SwiftUI cannot express
- Advanced animations with UIKit dynamics
- Frameworks that require UIViewController
- Legacy codebases that already use UIKit
- When you need more control over the render pipeline
Q: What is the difference between @StateObject and @ObservedObject?
@StateObject creates and owns the object, keeping it alive across view updates. @ObservedObject observes an externally created object and does not own its lifecycle. Use @StateObject when the view creates the object, and @ObservedObject when it receives the object from a parent.
Coding Challenges
Challenge 1: Reverse a Linked List
class ListNode<T> {
var value: T
var next: ListNode?
init(_ value: T) { self.value = value }
}
func reverseList<T>(_ head: ListNode<T>?) -> ListNode<T>? {
var prev: ListNode<T>?
var current = head
while let node = current {
let next = node.next
node.next = prev
prev = node
current = next
}
return prev
}
Challenge 2: Debounce Function
class Debouncer {
private var workItem: DispatchWorkItem?
let delay: TimeInterval
init(delay: TimeInterval) { self.delay = delay }
func debounce(action: @escaping () -> Void) {
workItem?.cancel()
workItem = DispatchWorkItem { action() }
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem!)
}
}
Challenge 3:LRUCache
class LRUCache<Key: Hashable, Value> {
private var cache: [Key: Value] = [:]
private var order: [Key] = []
let capacity: Int
init(capacity: Int) { self.capacity = capacity }
func get(_ key: Key) -> Value? {
guard let value = cache[key] else { return nil }
order.removeAll { $0 == key }
order.append(key)
return value
}
func put(_ key: Key, value: Value) {
if cache[key] != nil {
order.removeAll { $0 == key }
} else if order.count >= capacity {
let oldest = order.removeFirst()
cache.removeValue(forKey: oldest)
}
cache[key] = value
order.append(key)
}
}
Challenge 4: Combine Multiple Async Calls
func fetchDashboard() async throws -> Dashboard {
async let user = api.fetchUser()
async let posts = api.fetchPosts()
async let notifications = api.fetchNotifications()
let (u, p, n) = await (try user, try posts, try notifications)
return Dashboard(user: u, posts: p, notifications: n)
}
Architecture Discussions
MVVM
Explain MVVM and its benefits.
MVVM separates presentation (View) from business logic (ViewModel) from data (Model). The ViewModel exposes state through observable properties. Benefits include testability (ViewModel has no UI dependency), reusability (same ViewModel for different Views), and clear separation of concerns.
Clean Architecture
How do you structure a large iOS app?
Use layers with clear boundaries:
- Presentation: Views and ViewModels
- Domain: Use cases and business rules
- Data: Repositories and data sources
- Infrastructure: Networking, persistence, external services
Each layer depends only on the layer below it. Use dependency injection to manage dependencies.
SwiftUI Architecture
How do you manage state in a large SwiftUI app?
- Use @StateObject for view-owned objects
- Use @EnvironmentObject for shared state
- Use @State for simple local state
- Consider using an Actor for shared mutable state
- Keep views simple and move logic to ViewModels
System Design Questions
Design a social media feed:
- API layer with pagination and caching
- Repository pattern for data access
- ViewModel with observable state
- Lazy loading with infinite scroll
- Image caching with NSCache
- Offline support with CoreData
- Background refresh with BGTaskScheduler
Performance Discussion
How would you optimize a slow-scrolling list?
- Use Instruments Time Profiler to find bottlenecks
- Ensure cell reuse with List or LazyVStack
- Downsample images before display
- Use async image loading
- Reduce cell complexity
- Profile with Release builds on real devices
Quiz
1. What is the main difference between struct and class in Swift?
2. What problem does MVVM solve compared to MVC?
3. What is a retain cycle?
4. How do you handle multiple concurrent API calls in Swift?
Flashcards
Question
What is the difference between @StateObject and @ObservedObject?
Click to reveal answer
Answer
@StateObject creates and owns the object (persists across view updates). @ObservedObject observes an externally created object (does not own lifecycle).
Question
What are the main layers in Clean Architecture?
Click to reveal answer
Answer
Presentation (Views, ViewModels), Domain (Use cases), Data (Repositories), Infrastructure (Networking, Persistence).
Question
How do you break a retain cycle in a closure?
Click to reveal answer
Answer
Use a capture list with [weak self] or [unowned self] to prevent the closure from strongly capturing self.
Revision Notes
Key Takeaways
- 1. Know the difference between value and reference types
- 2. Explain ARC, retain cycles, and how to break them
- 3. Understand MVVM and Clean Architecture benefits
- 4. Be ready to code live: linked lists, caching, async patterns
- 5. Practice system design for common iOS features
Interview Tips
- • Think out loud during coding challenges to show your process
- • Ask clarifying questions before starting to code
- • Discuss trade-offs in architecture decisions
- • Show enthusiasm for iOS development and continuous learning
- • Prepare specific examples from your experience
Cheat Sheet
Interview Quick Reference
- struct: value type, copied on assignment
- class: reference type, shared reference
- weak: becomes nil on dealloc, Optional required
- unowned: does not become nil, crashes if accessed after dealloc
- MVVM: testability through separation
- async let: parallel async execution
- Capture lists break retain cycles in closures