What are dependency injection approaches for Combine in Swift?

In Swift, dependency injection is a design pattern that allows you to provide your classes with their dependencies from the outside. When combined with Apple's Combine framework, this can lead to more testable and modular code. Below are some common approaches to implement dependency injection in a Combine-based application.

Example of Dependency Injection in Combine

// Define a protocol for a service protocol DataService { func fetchData() -> AnyPublisher } // Create a concrete implementation of the DataService class ApiService: DataService { func fetchData() -> AnyPublisher { // Implement API call using Combine return URLSession.shared.dataTaskPublisher(for: URL(string: "https://api.example.com/data")!) .map { $0.data } .receive(on: DispatchQueue.main) .eraseToAnyPublisher() } } // ViewModel that requires a DataService class ViewModel { private let dataService: DataService @Published var data: Data? @Published var error: Error? init(dataService: DataService) { self.dataService = dataService } func loadData() { dataService.fetchData() .sink(receiveCompletion: { completion in if case let .failure(err) = completion { self.error = err } }, receiveValue: { data in self.data = data }) .store(in: &cancellables) } private var cancellables = Set() } // Usage in a view let viewModel = ViewModel(dataService: ApiService()) viewModel.loadData()

Combine Dependency Injection Swift SwiftUI Combine Framework Clean Architecture Testable Code ViewModel