Created
September 13, 2025 05:46
-
-
Save vlas-voloshin/2096bf5528db39b90e6fc15206eee3bd to your computer and use it in GitHub Desktop.
Replacement for StateObject property wrapper for Observable objects
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import SwiftUI | |
| /// A property wrapper type that instantiates an observable object. | |
| /// | |
| /// This is a wrapper for `State` that works with `Observable` values and provides "lazy" initialization semantics similar to `StateObject`. | |
| @MainActor @propertyWrapper | |
| struct LazyState<Value: Observable & AnyObject>: @preconcurrency DynamicProperty { | |
| var wrappedValue: Value { | |
| guard let value = storage.value else { | |
| fatalError("Attempted to access LazyState's value before it's constructed. Are you calling it outside of a View's body?") | |
| } | |
| return value | |
| } | |
| /// Creates a new state object with an initial wrapped value. | |
| /// | |
| /// See documentation of `StateObject.init(wrappedValue:)` for a description of this initializer's semantics and the caveats around initialization using external data. | |
| init(wrappedValue thunk: @autoclosure @escaping () -> Value) { | |
| // `State` initializer will reject the passed value if it was already initialized within a view with the same identity, leaving the existing storage intact | |
| _storage = State(initialValue: Storage(thunk)) | |
| } | |
| // MARK: - DynamicProperty | |
| func update() { | |
| storage.initializeIfNeeded() | |
| } | |
| // MARK: - Private | |
| @MainActor | |
| private final class Storage { | |
| private(set) var value: Value? | |
| private var thunk: (() -> Value)? | |
| init(_ thunk: @escaping () -> Value) { self.thunk = thunk } | |
| func initializeIfNeeded() { | |
| // Clear out initialization thunk once the value is constructed to release any intermediary resources | |
| if value == nil, let thunk = thunk.take() { | |
| value = thunk() | |
| } | |
| } | |
| } | |
| @State private var storage: Storage | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment