[quote='865440022, Engineer, /thread/806702?answerId=865440022#865440022']
However, in your example, since those environment variables wouldn't likely update very frequently (they're not really in a hot path) the cost of putting them in the environment is probably negligible.
[/quote]
Indeed, and now that I know that every write to any environment variable is not as egregious as I initially thought, then I'm a bit less concerned about this issue.
That said, I do want to revisit this a bit. In your demo, you were worried about writes in the hot path during a critical operation like scrolling.
What I'm finding on macOS isn't that I have "hot paths" but rather I have a lot of views being updated because of a very small change. These might be infrequent, the cost is high and noticeable.
An example would be keeping track of a selected objects on a canvas such that a bunch of inspector panels and other panes need to update their state based as the selection changes.
Selection changes are relatively infrequent (compared to scrolling) but a when they occur, a lot of views need to be updated. In my app, such a scenario is giving the application an overall "sluggish" feel as the user clicks around.
I wouldn't say that you need to go back to all your uses of environment values and change them to use @Observable classes, but if you're seeing performance issues, or building something new, it's worth considering.
One big issue I have with @Observable and @Environment is that I have to use a concrete type in @Environment if I want to be able to make an @Bindable reference. Ideally, I want the environment value to be generic. I can define it as being a protocol, but then I cannot convert the protocol to an @Bindable, or at least I don't know how.
Specifically, the following doesn't work:
struct Item {
var frame: CGRect
}
protocol SelectionProvider: Observable {
var selectedItem: Item? { get }
}
@Observable
final class Document: SelectionProvider {
var selectedItem: Item?
}
extension EnvironmentValues {
@Entry var selectionProvider: (any SelectionProvider)?
}
struct SampleView: View {
@Environment(\.selectionProvider) private var selectionProvider
var body: some View {
// Error: 'init(wrappedValue:)' is unavailable:
// The wrapped value must be an object that conforms to Observable
@Bindable var selectionProvider = selectionProvider
}
}
Topic:
UI Frameworks
SubTopic:
SwiftUI
Tags: