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?