A Swift Package for a modern approach to Service Locator for Swift and SwiftUI.
Container is inspired by the excellent Factory library, but designed as a lightweight alternative. This library focuses on simplicity while providing essential dependency injection features with fluent API and automatic mock injection for previews and tests. Rob-Yoo gives me strong inspiration that how to manage singleton instance when reference count is 0. Thank you for your advice :)
Add Container to your project using Swift Package Manager. In Xcode:
- Go to File → Add Package Dependencies
- Enter the repository URL:
https://github.com/donggyushin/Container - Select the version you want to use
Or add it to your Package.swift:
dependencies: [
.package(url: "https://github.com/donggyushin/Container", from: "1.3.4")
]Register your dependencies using the fluent Factory API:
import Container
protocol Repository {
func fetchData() -> String
}
class RepositoryImpl: Repository {
func fetchData() -> String { "Real data" }
}
class RepositoryMock: Repository {
func fetchData() -> String { "Mock data" }
}
extension Container {
var repository: Factory<Repository> {
self {
RepositoryImpl()
}
.shared // Optional: Use shared scope (singleton-like)
.onPreview {
RepositoryMock() // Automatically used in Xcode Previews and Tests
}
}
}Use the @Injected property wrapper for clean dependency injection:
class ViewModel: ObservableObject {
@Injected(\.repository) private var repository
func loadData() {
let data = repository.fetchData()
// Use data...
}
}You can also access dependencies directly:
// Method 1: Function call syntax
let repo = Container.shared.repository()
// Method 2: Wrapped value property
let repo = Container.shared.repository.wrappedValueContainer supports two scopes:
.shared: Creates a singleton instance (default).unique: Creates a new instance each time
extension Container {
var uniqueService: Factory<SomeService> {
self {
SomeService()
}
.unique // New instance every time
}
}Set a default scope for all factories:
// In your app initialization
Container.shared.defaultScope = .shared- iOS 13.0+
- macOS 10.15+
- watchOS 6.0+
- tvOS 13.0+
- Swift 5.9+
donggyushin