What is dependency injection in Swift/iOS?
Answer
Dependency Injection (DI) provides objects with their dependencies rather than having them create their own — enabling testability, flexibility, and loose coupling. Constructor injection (recommended): protocol NetworkServiceProtocol { func fetchUsers() async throws -> [User] } class NetworkService: NetworkServiceProtocol { func fetchUsers() async throws -> [User] { /* real API call */ } } class MockNetworkService: NetworkServiceProtocol { func fetchUsers() async throws -> [User] { return [User(id: 1, name: "Test")] } } class UserListViewModel { private let networkService: NetworkServiceProtocol init(networkService: NetworkServiceProtocol = NetworkService()) { self.networkService = networkService } func loadUsers() async { let users = try? await networkService.fetchUsers() } } // Production: let vm = UserListViewModel() // Uses real service // Testing: let vm = UserListViewModel(networkService: MockNetworkService()). Property injection: class ViewController { var viewModel: ViewModel! // Set from coordinator }. Method injection: func process(using service: ServiceProtocol) { service.doWork() }. DI containers/frameworks: Swinject — register/resolve dependencies in a container: let container = Container() container.register(NetworkServiceProtocol.self) { _ in NetworkService() } container.register(UserListViewModel.self) { r in UserListViewModel(networkService: r.resolve(NetworkServiceProtocol.self)!) }. Benefits: easily swap implementations (real vs mock), unit test without side effects, clearer dependencies, Single Responsibility Principle. Environment injection (SwiftUI): struct ContentView: View { @EnvironmentObject var userService: UserService }.
Previous
What is the Keychain and when do you use it?
Next
What is the difference between synchronous and asynchronous operations in iOS?