Skip to content

Repository files navigation

iOS Interview Practice Projects

Four Xcode projects designed for senior iOS interview preparation, covering concurrency patterns, SwiftUI development, unit testing, and advanced Swift concurrency.

Requirements: Xcode 15+, iOS 17+


Quick Start

git clone https://github.com/christopherkmoore/iOS-Practice.git
cd iOS-Practice

Each project includes a pre-generated .xcodeproj. Open any project directly:

open ConcurrencyBugHunt/ConcurrencyBugHunt.xcodeproj
open SwiftUIBuilder/SwiftUIBuilder.xcodeproj
open TestabilityWorkshop/TestabilityWorkshop.xcodeproj
open ConcurrencyWorkshop/ConcurrencyWorkshop.xcodeproj

Using xcodegen? Each project also includes a project.yml for regeneration:

cd ConcurrencyBugHunt && xcodegen generate

Projects Overview

1. ConcurrencyBugHunt

Purpose: Code review practice — identify and fix concurrency bugs

How to use:

  • Run the app and navigate to each exercise
  • Each view contains intentionally buggy code
  • Read the code, identify the bug(s), then verify by running
  • Try to fix each bug before looking at solutions
SectionExercisesKey Bugs
GCD IssuesRace ConditionUnsynchronized shared mutable state
Main Thread ViolationUI updates from background thread
DeadlockSync dispatch to current queue, lock ordering
Async/AwaitTask CancellationMissing cancellation checks, stale results
Actor ReentrancyState changes during await suspension
Unstructured Task LeakTasks outliving views, missing cleanup
CombinePublisher Retain CycleStrong self in sink closures
Missing CancellableSubscriptions not stored

2. SwiftUIBuilder

Purpose: Build UI iteratively with mock API data

How to use:

  • Each exercise is a complete, working implementation
  • Study the patterns, then try recreating from scratch
  • Modify and extend to practice variations
SectionExercisesPatterns Covered
ListsBasic API Listasync/await data loading, error states
Pull to Refresh.refreshable, last-updated timestamp
Search & Filter.searchable, debounced search, combined filters
GridsPhoto GridLazyVGrid, category filtering, sheet presentation
Adaptive GridGridItem(.adaptive), list/grid toggle with animation
NavigationMaster-DetailNavigationLink(value:), navigationDestination
Modal Presentation.sheet, .fullScreenCover, .confirmationDialog, .alert
StateForm ValidationReal-time validation, password strength, submit gating
Shared State@StateObject, @EnvironmentObject, cart pattern

Shared Resources:

  • MockAPIService.swift — Actor-based mock API with simulated delays and random failures
  • Models: User, Post, Photo, Product

3. TestabilityWorkshop

Purpose: Refactor untestable code and write comprehensive tests

How to use:

  1. Read the "Before" (untestable) code in each exercise
  2. Study the "After" (testable) refactored version
  3. Examine the corresponding test file
  4. Practice writing tests yourself before looking at solutions
  5. Run tests with Cmd+U
SectionExerciseRefactoring Pattern
Dependency InjectionSingleton DependenciesExtract protocols, inject via initializer
Network CouplingHTTPClient protocol, mock responses
Date/TimeDateProviding protocol, controllable time
Side EffectsUserDefaultsKeyValueStore protocol, in-memory store
File SystemFileSystemProtocol, in-memory fake
ArchitectureViewModel Testing@MainActor, state transitions, @Published
Protocol MockingSpy/Stub/Fake patterns, call verification
AsyncAsync/Await TestingAsync test methods, Task cancellation

Test Target Structure:

TestabilityWorkshopTests/
├── Mocks/TestMocks.swift # Reusable mock implementations
├── SingletonExerciseTests.swift
├── NetworkCouplingExerciseTests.swift
├── DateTimeExerciseTests.swift
├── UserDefaultsExerciseTests.swift
├── FileSystemExerciseTests.swift
├── ViewModelExerciseTests.swift
├── ProtocolMockingExerciseTests.swift
└── AsyncTestingExerciseTests.swift

4. ConcurrencyWorkshop

Purpose: Deep-dive into Swift Concurrency and Combine with interactive learning

How to use:

  • Each module has three tabs: Try It (interactive demo), Learn (Q&A), Code (full source)
  • Run the demos to see concurrency patterns in action
  • Study the Q&A section for conceptual understanding
  • Review the source code and try exercises
SectionModulesPatterns Covered
AsyncSequencesConsuming AsyncSequencefor await, cancellation, breaking early
AsyncStreamyield, finish, onTermination, error handling
Bridging DelegatesWrapping delegate APIs with continuations
ContinuationsChecked & UnsafewithCheckedContinuation, timeout patterns, one-resume rule
Combine OperatorsCombining PublisherscombineLatest, merge, zip
Transforming StreamsflatMap, switchToLatest, schedulers
SendableThread SafetySendable protocol, @unchecked Sendable, crossing isolation
MainActorUI Patterns@MainActor, nonisolated, Swift 6 strict concurrency

Module Structure:

  • Each view includes working code examples you can run
  • Q&A sections explain the "why" behind each pattern
  • Exercises challenge you to extend or modify the code

Topics Covered

Concurrency

  • GCD: DispatchQueue, serial vs concurrent, sync vs async
  • Race conditions and data races
  • Main thread safety for UI updates
  • Deadlocks (queue reentry, lock ordering)
  • Swift Concurrency: async/await, Task, TaskGroup
  • Task cancellation and cooperative cancellation
  • Actor isolation and reentrancy
  • Structured vs unstructured concurrency
  • Combine: Publishers, Subscribers, AnyCancellable, retain cycles
  • AsyncSequence and for await loops
  • AsyncStream for bridging imperative code
  • Continuations: withCheckedContinuation, withUnsafeContinuation
  • Sendable protocol and thread-safe types
  • @MainActor and UI isolation patterns
  • Swift 6 strict concurrency preparation

SwiftUI

  • State management: @State, @Binding, @StateObject, @ObservedObject, @EnvironmentObject
  • Lists and ForEach
  • LazyVGrid/LazyHGrid with GridItem
  • Navigation: NavigationStack, NavigationLink, navigationDestination
  • Sheets, full-screen covers, alerts, confirmation dialogs
  • .searchable and .refreshable modifiers
  • .task for async data loading
  • Form validation patterns
  • Animations and transitions

Testing (XCTest)

  • Test structure: Arrange-Act-Assert
  • setUp() and tearDown()
  • Dependency injection for testability
  • Protocol-based mocking (Stub, Spy, Fake)
  • Testing @Published properties
  • @MainActor test classes for ViewModels
  • Async test methods (func test_x() async)
  • Testing error cases with XCTAssertThrowsError
  • Verifying mock interactions (call counts, arguments)

Swift Fundamentals (embedded throughout)

  • Protocols and protocol extensions
  • Generics
  • Value types vs reference types
  • Access control
  • Error handling
  • Closures and capture lists ([weak self])
  • Codable
  • Result type

Interview Practice Tips

For Code Review (ConcurrencyBugHunt)

  1. Read systematically — Don't jump to conclusions
  2. Look for shared mutable state — Who reads? Who writes? When?
  3. Trace the thread — Which queue/actor is this running on?
  4. Check completion handlers — Are they always called? Only once?
  5. Verify cancellation — Is Task.isCancelled checked after awaits?

For Building UI (SwiftUIBuilder)

  1. Start with the data model — What state do you need?
  2. Choose the right property wrapper — Who owns this state?
  3. Handle loading/error/empty states — Always show something
  4. Test on device — Simulators hide performance issues

For Testing (TestabilityWorkshop)

  1. Test behavior, not implementation — What should happen, not how
  2. One assertion focus per test — Tests should fail for one reason
  3. Use descriptive test namestest_methodName_condition_expectedResult
  4. Inject everything — If you can't inject it, you can't test it
  5. Reset mocks in tearDown — Tests must be independent

Running the Projects

# Open in Xcode
open ConcurrencyBugHunt/ConcurrencyBugHunt.xcodeproj
open SwiftUIBuilder/SwiftUIBuilder.xcodeproj
open TestabilityWorkshop/TestabilityWorkshop.xcodeproj
open ConcurrencyWorkshop/ConcurrencyWorkshop.xcodeproj
# Run tests (TestabilityWorkshop)# Cmd+U in Xcode, or:
xcodebuild test -project TestabilityWorkshop/TestabilityWorkshop.xcodeproj \
-scheme TestabilityWorkshop \
-destination 'platform=iOS Simulator,name=iPhone 15'

File Structure

iOS-Practice/
├── README.md # This file
├── ConcurrencyBugHunt/
│ ├── ConcurrencyBugHuntApp.swift
│ ├── ContentView.swift
│ └── Exercises/
│ ├── GCD/
│ ├── AsyncAwait/
│ └── Combine/
├── SwiftUIBuilder/
│ ├── SwiftUIBuilderApp.swift
│ ├── ContentView.swift
│ ├── Shared/MockAPIService.swift
│ └── Exercises/
│ ├── List/
│ ├── Grid/
│ ├── Navigation/
│ └── State/
├── TestabilityWorkshop/
│ ├── TestabilityWorkshopApp.swift
│ ├── ContentView.swift
│ ├── Exercises/
│ │ ├── DependencyInjection/
│ │ ├── SideEffects/
│ │ ├── Architecture/
│ │ └── Async/
│ └── TestabilityWorkshopTests/
│ ├── Mocks/TestMocks.swift
│ └── *Tests.swift
└── ConcurrencyWorkshop/
├── ConcurrencyWorkshopApp.swift
├── ContentView.swift
├── Shared/ # Reusable tab views, code viewer
├── ModuleContent/ # Q&A and exercise content
└── Modules/
├── AsyncSequences/
├── Continuations/
├── CombineOperators/
├── Sendable/
└── MainActor/

About

Practice problems to help you ace your interview!

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages