The "@Environment" keyword in SwiftUI
Today, I will show what the @Environment
keyword is and how it works.
Overview
@Environment
is a property wrapper in SwiftUI. It is used to access and read (but it is not allowed to write) environment values.
To dive deeper, let me first explain about environment values.
About environment values
Apps made with SwiftUI display views based on a view hierarchy structure, which consists of views as parents and children. These views have their own underlying data. In SwiftUI, some of data, such as locale and color scheme, are predefined and you can read them. Note that they are read-only and you cannot directly write to them.
About @Environment
The @Environment
property wrapper is a way to access environment values. Here is an example:
struct ExampleView: some View {
@Environment(\.colorScheme) var colorScheme: ColorScheme
if colorScheme == .dark {
DarkContent()
else {
LightContent()
}
}
In this way, you can instantiate a variable with @Environment
and the key path. If the current value of the colorScheme
is dark, the ExampleView
displays the DarkContent
and if the current value is not dark it displays the LightContent
.
To be detailed, the property wrapper @Environment
generates a computed property with a getter that retrieves the value using the specified key path (\.colorScheme
in this case). The wrappedValue
of the Environment
struct is used to access the actual value. Therefore, the code above is equivalent to the following:
struct ExampleView: View {
// @Environment(\.colorScheme) var colorScheme: ColorScheme
var colorScheme: ColorScheme {
get {
return Environment(\.colorScheme).wrappedValue
}
}
if colorScheme == .dark {
DarkContent()
else {
LightContent()
}
}
List of environment values
Here is a list of important and common environment values:
colorScheme
: The current color scheme (light or dark) of the environment.locale
: The current locale of the environment.calendar
: The current calendar of the environment.timeZone
:The current time zone of the environment.horizontalSizeClass
: The current horizontal size class of the environment (regular or compact).verticalSizeClass
: The current vertical size class of the environment (regular or compact).layoutDirection
: The current layout direction of the environment (left-to-right or right-to-left).accessibilityEnabled
: A Boolean value indicating whether accessibility features are enabled.editMode
: The edit mode of the current view (active or inactive).isSearching
: A Boolean value indicating whether a search is currently active.
How to create a custom environment value
In addition to the built-in environment values, you can create custom environment values. Here is an example:
struct MyCustomEnvironmentKey: EnvironmentKey {
static var defaultValue: String = "default value"
}
extension EnvironmentValues {
var myCustomValue: String {
get { self[MyCustomEnvironmentKey.self] }
set { self[MyCustomEnvironmentKey.self] = newValue }
}
}
As shown in the example above, you first have to define a struct that conform to the EnvironmentKey
protocol for the key to of the environment value. Then, you have to extend the EnvironmentValues
struct, where all the environment values are defined, to add the new environment value.
Now, you can access the new custom environment value using the @Environment
property wrapper:
struct MyView: View {
@Environment(\.myCustomValue) var customValue
var body: some View {
Text("Custom Value: \(customValue)")
}
}
struct ParentView: View {
var body: some View {
MyView()
.environment(\.myCustomValue, "Custom Value") // assign a value that is different from default value
}
}