Entry Macro for Custom SwiftUI Environment Values

The Entry macro reduces the boilerplate when customizing the SwiftUI environment.

Creating New Environment Values - A Recap

Adding our own values to the SwiftUI environment is a common operation but it requires some boilerplate code each time. See SwiftUI Custom Environment Values for an example but here’s a quick recap:

  1. Create the environment key with a default value:

    private struct CaptionColorKey: EnvironmentKey {
      static let defaultValue = Color(.secondarySystemBackground)
    }
    
  2. Extend the environment adding a getter/setter for our key:

    extension EnvironmentValues {
      var captionBackgroundColor: Color {
        get { self[CaptionColorKey.self] }
        set { self[CaptionColorKey.self] = newValue }
      }
    }
    

    At this point we can already use our custom environment value:

    ContentView()
      .environment(\.captionBackgroundColor, .yellow)
    

    Then in the ContentView:

    struct ContentView: View {
      @Environment(\.captionBackgroundColor) var captionBackgroundColor
      var body: some View {
         Text("Hello, world!")
             .background(captionBackgroundColor)
      }
    }
    
  3. An optional third step adds a view modifier to allow a more compact syntax:

    extension View {
      func captionBackgroundColor(_ color: Color) -> some View {
        environment(\.captionBackgroundColor, color)
      }
    }
    

    That allows us to write:

    ContentView()
      .captionBackgroundColor(.yellow)
    

The Entry macro helps us with the first two steps.

Using the Entry Macro

The Entry macro allows us to replace the first two steps, directly extending the environment:

extension EnvironmentValues {
  @Entry var captionBackgroundColor: Color = 
    Color(.secondarySystemBackground)
}

Expanding the macro shows us the generated code:

extension EnvironmentValues {
  {
    get {
      self[__Key_captionBackgroundColor.self]
    }
    set {
      self[__Key_captionBackgroundColor.self] = newValue
    }
  }
  private struct __Key_captionBackgroundColor: SwiftUICore.EnvironmentKey {
    typealias Value = Color
    static var defaultValue: Value { Color(.secondarySystemBackground) }
  }
}

The Entry macro doesn’t help with the final optional step of adding a view modifier but it does remove the rest of the boilerplate. It also works for adding Transaction, ContainerValues, and FocusedValues, and works back to iOS 13 so there’s no need to wait to use it.

Learn More