https://gist.github.com/vanvoorden/37ff2b2f9a2a0d0657a3cc5624cc9139
Hi! I'm experimenting with the Entry
macro in a SwiftUI app. I'm a little confused about how to stored a defaultValue
to prevent extra work from creating this more than once.
A "legacy" approach to defining an Environment
variable looks something like this:
struct StoredValue { var value: String { "Hello, world!" } init() { print("StoredValue.init()") } } extension EnvironmentValues { var storedValue: StoredValue { get { self[StoredValueKey.self] } set { self[StoredValueKey.self] = newValue } } struct StoredValueKey: EnvironmentKey { static let defaultValue = StoredValue() } }
The defaultValue
is a static
stored property.
Here is a "modern" approach using the Entry
macro:
struct ComputedValue { var value: String { "Hello, world!" } init() { print("ComputedValue.init()") } } extension EnvironmentValues { @Entry var computedValue: ComputedValue = ComputedValue() }
From the perspective of the product engineer, it looks like I am defining another stored defaultValue
property… but this actually expands to a computed property:
extension EnvironmentValues { var computedValue: ComputedValue { get { self[__Key_computedValue.self] } set { self[__Key_computedValue.self] = newValue } } private struct __Key_computedValue: SwiftUICore.EnvironmentKey { static var defaultValue: ComputedValue { get { ComputedValue() } } } }
If I tried to use both of these Environment
properties in a SwiftUI component, it looks like I can confirm the computedValue
is computing its defaultValue
several times:
@main struct EnvironmentDemoApp: App { var body: some Scene { WindowGroup { ContentView() } } } struct ContentView: View { @Environment(\.computedValue) var computedValue @Environment(\.storedValue) var storedValue var body: some View { VStack { Image(systemName: "globe") .imageScale(.large) .foregroundStyle(.tint) Text("Hello, world!") } .padding() } }
And then when I run the app:
ComputedValue.init() StoredValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init() ComputedValue.init()
Is there any way to use the Entry
macro in a way that we store the defaultValue
instead of computing it on-demand every time?