69 lines
1.8 KiB
Swift
69 lines
1.8 KiB
Swift
import Foundation
|
|
|
|
public final class DIContainer: @unchecked Sendable {
|
|
|
|
public static let shared = DIContainer()
|
|
public private(set) var values = InjectionValues()
|
|
private var observers: [AnyKeyPath: [UUID: @Sendable () -> Void]] = [:]
|
|
private let lock = NSLock()
|
|
|
|
private init() {}
|
|
|
|
public func register<T>(
|
|
_ keyPath: WritableKeyPath<InjectionValues, T?>,
|
|
value: T
|
|
) {
|
|
lock.withLock {
|
|
values[keyPath: keyPath] = value
|
|
}
|
|
notifyObservers(for: keyPath)
|
|
}
|
|
|
|
public func resolve<T>(
|
|
_ keyPath: KeyPath<InjectionValues, T?>
|
|
) -> T {
|
|
lock.withLock {
|
|
guard let value = values[keyPath: keyPath] else {
|
|
fatalError(
|
|
"DIContainer: No value registered for \(keyPath). "
|
|
+ "Call DIContainer.shared.register(\\.key, value:) during app startup."
|
|
)
|
|
}
|
|
return value
|
|
}
|
|
}
|
|
|
|
@discardableResult
|
|
func addObserver<T>(
|
|
for keyPath: KeyPath<InjectionValues, T?>,
|
|
handler: @escaping @Sendable () -> Void
|
|
) -> UUID {
|
|
let id = UUID()
|
|
lock.withLock {
|
|
observers[keyPath, default: [:]][id] = handler
|
|
}
|
|
return id
|
|
}
|
|
|
|
func removeObserver(_ id: UUID) {
|
|
lock.withLock {
|
|
for keyPath in observers.keys {
|
|
observers[keyPath]?.removeValue(forKey: id)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func notifyObservers(for keyPath: AnyKeyPath) {
|
|
let handlers: [@Sendable () -> Void] = lock.withLock {
|
|
Array(observers[keyPath]?.values ?? [])
|
|
}
|
|
handlers.forEach { $0() }
|
|
}
|
|
|
|
public func reset() {
|
|
lock.withLock {
|
|
values = InjectionValues()
|
|
observers.removeAll()
|
|
}
|
|
}
|
|
}
|