The @Entry macro in SwiftUI allows you to define custom environment values without writing boilerplate code. While introduced in Xcode 16, you can use it from iOS 13 and up since it’s a Swift Macro that generates backward-compatible code.
The new macro can be used for environment values, as well as for transaction, container, and focused values. In this article, we’ll be focusing on environment values only.
What are Environment Values?
Environment values are a way to share data across the view hierarchy in SwiftUI. They are essentially key-value pairs that provide views with access to data that is common throughout the app or specific to a part of the view hierarchy.
This mechanism helps maintain a clean and efficient data flow without explicitly passing data through multiple layers of views. You can access an environment value using the @Environment or @EnvironmentObject property wrapper for which I wrote dedicated articles:
- @EnvironmentObject explained for sharing data between views in SwiftUI
- Using @Environment in SwiftUI to link Swift Package dependencies
Using the @Entry macro to create custom environment values
The @Entry macro is a so-called attached macro and can be used as follows:
extension EnvironmentValues {
@Entry var primaryTheme: Theme = .init(primaryColor: .accentColor)
}
It’s called ‘entry’ since you create ‘an entry to a value’ in a given environment. In our case, we’re generating an entry to an environment value. However, you can also use it to create Transaction
, ContainerValues
, or FocusedValues
entries.
The example allows you to define a custom theme for your app, accessible throughout the view hierarchy. It’s a simple theme definition for the sake of this example:
@Observable
final class Theme {
var primaryColor: Color
init(primaryColor: Color) {
self.primaryColor = primaryColor
}
}
The macro generates code behind the scenes that looks as follows:
In other words, without using the macro we had to write the following code to make the same piece work:
extension EnvironmentValues {
var primaryTheme: Theme {
get {
self[PrimaryThemeKey.self]
}
set {
self[PrimaryThemeKey.self] = newValue
}
}
}
struct PrimaryThemeKey: EnvironmentKey {
static var defaultValue: Theme { .init(primaryColor: .accentColor) }
}
While writing this code might be fine for a single key, it quickly becomes a lot when you have to write many custom environment values. Replacing this boilerplate with the macro is an excellent code improvement.
Using the @Entry generated code in SwiftUI
Once you’ve added a custom entry using the @Entry macro, you can start reference its value as follows:
struct ThemedView: View {
@Environment(\.primaryTheme) private var primaryTheme: Theme
var body: some View {
Text("This text is using the theme's primary color")
.foregroundStyle(primaryTheme.primaryColor)
}
}
Since we defined our Theme
as observable, our view will automatically update when the primary color changes. Environment values are a great way to access common app data without manually passing it through the view hierarchy.
Conclusion
The @Entry macro is a great example of the added value macros can deliver. It’s great to see a new Xcode version adding backward-compatible features that reduce the code we have to write manually.
If you want to improve your SwiftUI knowledge, even more, check out the SwiftUI category page. Feel free to contact me or tweet me on Twitter if you have any additional tips or feedback.
Thanks!