Skip to content
advanced Phase 15 · iOS Interview Preparation

iOS Interview Preparation

Common iOS interview questions, coding challenges, and architecture discussions.

1h
5 problems
Topic Progress 0%

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:

  1. API layer with pagination and caching
  2. Repository pattern for data access
  3. ViewModel with observable state
  4. Lazy loading with infinite scroll
  5. Image caching with NSCache
  6. Offline support with CoreData
  7. Background refresh with BGTaskScheduler

Performance Discussion

How would you optimize a slow-scrolling list?

  1. Use Instruments Time Profiler to find bottlenecks
  2. Ensure cell reuse with List or LazyVStack
  3. Downsample images before display
  4. Use async image loading
  5. Reduce cell complexity
  6. Profile with Release builds on real devices

Quiz

1. What is the main difference between struct and class in Swift?

Question 1 options

2. What problem does MVVM solve compared to MVC?

Question 2 options

3. What is a retain cycle?

Question 3 options

4. How do you handle multiple concurrent API calls in Swift?

Question 4 options

Flashcards

Question

What is the difference between @StateObject and @ObservedObject?

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?

Answer

Presentation (Views, ViewModels), Domain (Use cases), Data (Repositories), Infrastructure (Networking, Persistence).

Question

How do you break a retain cycle in a closure?

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