SwiftQA Random

What is dependency inversion in iOS?

The precise definition — and the distinction that trips people up

Dependency Inversion Principle (DIP):

  1. High-level modules should not depend on low-level modules; both should depend on abstractions.
  2. Abstractions should not depend on details; details should depend on abstractions.

Dependency Injection (DI) is a technique — passing a dependency in rather than constructing it. You can have DI without DIP:

// Injection WITHOUT inversion
final class ProfileViewModel {
    private let repository: NetworkUserRepository  // still concrete!
    init(repository: NetworkUserRepository) { self.repository = repository }
}
// Injection WITH inversion
protocol UserRepository {
    func fetchUser(id: String) async throws -> User
}
final class ProfileViewModel {
    private let repository: UserRepository
    init(repository: UserRepository) { self.repository = repository }
}
final class NetworkUserRepository: UserRepository {
    func fetchUser(id: String) async throws -> User { ... }
}

Why “inversion” is the right word

The abstraction is conceptually owned by the high-level/policy side, not the low-level detail.

Where this shows up

Clean Architecture, multi-team contracts, third-party SDK wrapping, testability everywhere.

A common half-measure worth naming

Injecting a concrete class instance is better than a singleton, but it’s not full DIP. Sometimes that’s fine — introducing an abstraction with exactly one real implementation and no test-double need is ceremony without payoff.

Dependency InjectionDependency Inversion
What it isA technique: pass dependencies inA design principle: both sides depend on a shared abstraction
Can exist alone?Yes — can inject a concrete typeNo — requires an abstraction layer
What it solvesConfigurability, testabilityTrue decoupling

One-liner if pressed: “Dependency injection is passing a dependency in rather than constructing it; dependency inversion is the stronger claim that both the high-level and low-level code should depend on a shared abstraction that the high-level side effectively owns, so the low-level detail conforms to what the policy needs rather than the policy adapting to whatever the detail happens to expose.”