Adding custom keys to the SwiftUI environment

Published on: January 10, 2022

Sometimes you’ll find yourself in a situation where you want to conveniently pass some object down via the SwiftUI environment. An easy way to do this is through the .environmentObject view modifier. The one downside of this view modifier and corresponding @EnvironmentObject property wrapper is that the object you add to the environment must be an observable object.

Luckily, we can extend the SwiftUI environment to add our own objects to the @Environment property wrapper without the need to make these objects observable.

For example, your app might have to do some date formatting, and maybe you’re looking for a convenient way to pass a default date formatter around to your views without explicitly passing this date formatter around all the time. The SwiftUI environment is a convenient way to achieve this.

To add our date formatter to the environment, we need to define an EnvironmentKey, and we need to add a computed property to the EnvironmentValues object. Here’s what this looks like:

private struct DateFormatterKey: EnvironmentKey {
    static let defaultValue: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "MM/dd/yyyy"
        return formatter
    }()
}

extension EnvironmentValues {
    var dateFormatter: DateFormatter {
        get { self[DateFormatterKey.self] }
        set { self[DateFormatterKey.self] = newValue }
    }
}

This code conveniently sets up a default date formatter (which is required by the EnvironmentKey protocol). I’ve also added a computed property to EnvironmentValues to make the date formatter object available in my SwiftUI views.

Using this custom environment value is done as follows:

struct LabelView: View {
    @Environment(\.dateFormatter) var dateFormatter
    @State var date: Date

    var body: some View {
        Text("date: \(dateFormatter.string(from: date))")
    }
}

Adding your own keys to the SwiftUI environment can be done for all kinds of reasons. You can use the environment for small objects like the date formatter in this example. But you can even use the environment to pass around more complex objects. For example, you could pass your networking stack around through the SwiftUI environment if this suits your needs.

Hopefully this quick tip is useful for you! I’d love to hear about the kind of things you’re using the SwiftUI environment for in your apps, so make sure to shoot me a Tweet if you’d like to tell me about your experiences.

Categories

Quick Tip SwiftUI

Subscribe to my newsletter