Add DIContainer with observer registry
This commit is contained in:
parent
22213037ca
commit
2280142fe1
1 changed files with 69 additions and 0 deletions
69
Sources/LuminateDI/DIContainer.swift
Normal file
69
Sources/LuminateDI/DIContainer.swift
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
import Foundation
|
||||
|
||||
public final class DIContainer {
|
||||
|
||||
public static let shared = DIContainer()
|
||||
public private(set) var values = InjectionValues()
|
||||
private var observers: [AnyKeyPath: [UUID: () -> 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 () -> 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: [() -> Void] = lock.withLock {
|
||||
Array(observers[keyPath]?.values ?? [])
|
||||
}
|
||||
handlers.forEach { $0() }
|
||||
}
|
||||
|
||||
public func reset() {
|
||||
lock.withLock {
|
||||
values = InjectionValues()
|
||||
observers.removeAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue