Skip to content

Commit

Permalink
EnvironmentLazyObject
Browse files Browse the repository at this point in the history
  • Loading branch information
NikSativa committed Jul 13, 2024
1 parent 667ae6a commit 84ee295
Showing 1 changed file with 50 additions and 0 deletions.
50 changes: 50 additions & 0 deletions Source/PropertyWrapper/EnvironmentLazyObject.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#if canImport(SwiftUI)
import Combine
import SwiftUI

@propertyWrapper
public struct EnvironmentLazyObject<Value: ObservableObject>: DynamicProperty {
@EnvironmentObject private var container: ObservableResolver
@ObservedObject private var holder: Holder<Value> = .init()

public var wrappedValue: Value {
if let instance = holder.instance {
return instance
}

let instance: Value = container.resolve(named: name, with: arguments)
holder.instance = instance
return instance
}

private let name: String?
private let arguments: Arguments

public init(named name: String? = nil,
with arguments: Arguments = .init()) {
self.name = name
self.arguments = arguments
}

public var projectedValue: Binding<Value> {
assert(holder.instance != nil, "`projectedValue` is not available while the `wrappedValue` is not initialized. Should never happen.")
return $holder.instance
}
}

private final class Holder<Value: ObservableObject>: ObservableObject {
private var observers: Set<AnyCancellable> = []

var instance: Value! {
didSet {
if oldValue !== instance {
assert(observers.isEmpty, "Subscribed to `objectWillChange` multiple times. Should never happen.")
observers = []
instance.objectWillChange.sink { [unowned self] _ in
objectWillChange.send()
}.store(in: &observers)
}
}
}
}
#endif

0 comments on commit 84ee295

Please sign in to comment.