Dependency injection

Architecture & patterns Mid-level Swift 5.9+ iOS 17+ Reviewed By Alok Singh

Spot the bug

This view model can't be tested without the real network. Tap the line to change.

  1. @MainActor @Observable
  2. final class OrdersViewModel {
  3. var orders: [Order] = []
  4. func load() async throws {
  5. orders = try await APIService.shared.fetchOrders()
  6. }
  7. }
Hint 1 of 1

Where does the view model get its service from?

Choose an answer, then open Show answer below to check it.

Show answer
  • Answer: line 5 orders = try await APIService.shared.fetchOrders()

Line 5 reaches for a hidden singleton. Inject a small OrdersLoading protocol through init and call it, so tests can pass a stub.

30-second answer

Dependency injection means a type receives what it needs instead of creating or fetching it globally. Prefer initializer injection with protocol types, defaulting to real implementations at the composition root. It makes dependencies visible, lets tests pass stubs, and lets previews use fake data. SwiftUI's environment is injection for view trees.

Practise saying it · 30 s. No recording, just a timer

Explain dependency injection.

Say your answer out loud, then check which of these points you covered:

  • Receive, don't fetch
  • Initializer injection
  • Protocols for test doubles
  • Composition root

Deep dive

Constructor injection > property injection > service locators.

Keep protocols small, shaped by what the consumer needs.

One composition root builds the object graph at launch.

Libraries exist, but plain initializers go a long way.

Common mistakes

  • Reaching for .shared inside types.
  • Huge protocols mirroring the whole service.

Senior take & follow-ups

Seniors make dependencies explicit and keep the wiring in one place.

Follow-up questions

Think of your answer first, then open the hint.

  1. Is a singleton always wrong?

    Show hint

    No, but inject it instead of referencing it directly.

  2. How does SwiftUI do injection?

    Show hint

    Environment values and @Environment.

Suggest a fix if something here is wrong or out of date.