Mastering SwiftUI: @Environment Properties Deep Dive

SwiftUI, created by Apple in 2019, has transformed the way developers design user interfaces for their iOS, macOS, watchOS, and tvOS applications. It simplifies the process by providing a clear and concise way for developers to describe the user interface using a declarative syntax. One of its powerful features is the @Environment property wrapper. In this article, we’ll explore the @Environment property wrapper in SwiftUI, understanding its purpose, when to use it, and how it contributes to building scalable and maintainable SwiftUI applications.

What is @Environment?

In SwiftUI, the @Environment property wrapper is like a storage place for values that affect how a view looks. It’s where things like color schemes, font styles, and other settings are kept. The @Environment property wrapper helps us grab these values and use them in our SwiftUI views.

Basics of Usage:

Let’s start with a basic example. Imagine you want to change the text color in your SwiftUI view based on whether the user prefers a light or dark color scheme.

struct ColorSchemeDemoView: View {
    @Environment(\.colorScheme) var colorScheme

    var body: some View {
        Text("Hello, SwiftUI!")
            .foregroundColor(colorScheme == .dark ? .white : .black)
    }
}

In this example, we’re using the @Environment(\.colorScheme) property wrapper to get the current color scheme. The text color is then set accordingly – white for dark mode and black for light mode.

Note:  ‘\.colorScheme’ is one of the in-built EnvironmentValue.

Other SwiftUI Predefined Environment Values

Besides color schemes, SwiftUI gives us other environment values we can use. Here are a few examples:

  • \.locale: Tells us the user’s language and region.
  • \.sizeCategory: Informs us about the user’s preferred text size.
  • \.horizontalSizeClass and \.verticalSizeClass: Give us information about the device’s size class.
  • \.presentationMode: Helps us know how a view is being presented.
struct EnvironmentValuesDemoView: View {
    @Environment(\.locale) var locale
    @Environment(\.sizeCategory) var sizeCategory
    @Environment(\.horizontalSizeClass) var horizontalSizeClass
    @Environment(\.verticalSizeClass) var verticalSizeClass
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        // Do something based on these environment values
        // ...
    }
}

Making Your Own Environment Values

If the built-in values aren’t enough, you can create your own. Creating custom environment values in SwiftUI allows you to define and manage your own set of properties that influence the appearance or behavior of your views. This is particularly useful when you need to share data or configuration settings across multiple views within your SwiftUI application. Here’s a step-by-step explanation and example usage in SwiftUI:

Define a Custom Environment Key –

EnvironmentKey is a protocol that you can adopt to define your own custom environment values. So, it is a key for accessing values in the environment.

Begin by creating your custom environment key, which serves as the identifier for the custom environment value:

struct MyCustomEnvironmentKey: EnvironmentKey {
    static let defaultValue: String = "Default Value"
}

MyCustomEnvironmentKey acts as a wrapper for a string value, Struct MyCustomEnvironmentKey extends  EnvironmentKey protocol and  ‘defaultValue’ is associated type, that must define in our custom EnvironmentKey.

extension EnvironmentValues {
    var myCustomValue: String {
        get { self[MyCustomEnvironmentKey.self] }
        set { self[MyCustomEnvironmentKey.self] = newValue }
    }
}
  • extension EnvironmentValues: This is an extension for the EnvironmentValues type. In SwiftUI, EnvironmentValues is a container for values that are shared within the environment of a SwiftUI view hierarchy.
  • var myCustomValue: String: This declares a computed property named myCustomValue of type String within the extension. Computed properties are used to calculate a value rather than storing it.
  • get { self[MyCustomEnvironmentKey.self] }: This is the getter for the myCustomValue property. It retrieves the value associated with the MyCustomEnvironmentKey type from the environment.
  • set { self[MyCustomEnvironmentKey.self] = newValue }: This is the setter for the myCustomValue property. It sets the value of the MyCustomEnvironmentKey type in the environment to the new value provided.

In summary, this code extends the EnvironmentValues type in SwiftUI by adding a computed property myCustomValue of type String. This property allows you to get and set a custom value (MyCustomEnvironmentKey) in the SwiftUI environment. It’s a way to create a custom environment key for your SwiftUI app.

Access the Custom Environment Value in a View

The custom value you set in the environment can be accessed using the @Environment property wrapper. For example:

struct ContentView: View {
    @Environment(\.myCustomValue) var customValue

    var body: some View {
        Text("Custom Value: \(customValue)")
    }
}

In this case, ContentView can access the customValue.

Create a Custom Modifier:

Define a custom view modifier to apply the custom environment value:

struct SetCustomEnvironmentValue: ViewModifier {
    let value: String

    func body(content: Content) -> some View {
        content.environment(\.myCustomValue, value)
    }
}

This modifier takes a value and assigns it as the custom environment value for the view hierarchy.

Apply the Custom Modifier:

Apply the custom environment modifier to a view where you want to utilize the custom environment value:

struct ContentView: View {
    var body: some View {
        NavigationView {
            VStack {
                 NavigationLink(destination: NextNavigationView()
                    .modifier(SetCustomEnvironmentValue(value: "Updated Value"))) {
                     Text("Go to next view")
                    Spacer()
                }
            }
          
        }
    }
}
struct NextNavigationView: View {
    @Environment(\.myCustomValue) var customValue

    var body: some View {
        Text(customValue)
    }
}

Here, in above example, in  ‘ContentView’ we redirect to ‘NextNavigationView, We set modifier to change ‘myCustomValue’. When you will access ‘myCustomValue’ in ’NextNavigationView’. It will simply display updated value. 

Note: Remember that SwiftUI environment values are scoped to the view hierarchy, so you’ll be able to access them within the subtree of the view where you applied the environment modifier.

If you want apply updated value in whole app, you can apply it on @main entry point.

@main
struct ExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .modifier(SetCustomEnvironmentValue(value: "YourCustomValue"))

         }
    }
}

Conclusion:

The @Environment property wrapper in SwiftUI simplifies how we access and manage crucial information about the app’s environment. Whether it’s adapting to different themes, handling user authentication, or customizing navigation, @Environment proves to be a versatile tool, contributing to the clarity and efficiency of SwiftUI development.

One thought on “Mastering SwiftUI: @Environment Properties Deep Dive

Leave a Reply

Your email address will not be published. Required fields are marked *