Here's the definition of EnvironmentKey
:
public protocol EnvironmentKey {
associatedtype Value
static var defaultValue: Self.Value { get }
}
I'm confused as to the purpose of the defaultValue
property. Or perhaps I'm confused about the intended use of @Environment
. Let me explain...
Based on my testing, I know that the defaultValue
is being accessed. If you, for example, define the defaultValue
as a getter:
protocol MyInjector: EnvironmentKey {
static var defaultValue: Foo {
print("get default value!")
return Foo()
}
}
you'll find that SwiftUI frequently calls this property (because of this, in practice I define my defaultValue
as static let
).
When you add a breakpoint on the print statement and move down the stack it stops on the arrow below:
extension EnvironmentValues {
var myInjector: Foo {
get { self[MyInjector.self] } <-----------------
set { self[MyInjector.self] = newValue }
}
}
Further down in the stack is the line in my component's init
where I access the following variable:
@Environment(\.myInjector) var foo: Foo
That is, it seems to access defaultValue
any time a SwiftUI view with an @Environment
variable is re-rendered.
I think that the internal implementation of @Environment
needs to set this default value before it determines the actual value as a way to avoid making the variable declaration optional.
Finally, I also experimented with adding @Environment
to an ObservableObject
in the hopes that it would have access to the same "environment" as the SwiftUI view tree.
class Bar: ObservableObject {
@Environmenet(\.myInjector var foo: Foo
}
Unfortunately, that was not the case and the instance that Bar
received was different than the instance I had injected via View.environment(\.myInjector, Foo())
.
I also found, btw that I could use @Environment
to inject a global singleton by using the shared variable pattern:
protocol MyInjector: EnvironmentKey {
static let defaultValue = Foo()
}
and the same instance was available to SwiftUI views and any other class, but I'm not sure how that could be useful in any way.
So what is the purpose of defaultValue
? Is it simply, as I suspect, so that the internal implementation can assign an arbitrary value to the variable before the true value is determined, or is there something else going on?
IMO there are two reasons to have defaultValue
in this pattern (and I assume this was the intention):
1) to specify corresponding value type
2) to make environment value always valid (in usage of @Environment
)
In SwiftUI: Set Status Bar Color For a Specific View post you can find example of usage of this defaultValue
feature to easily connect via environment different parts of application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With