Thanks @crystalminds. They are nicely written articles and from a quick read appear to cover material I am not 100% familiar with so I will definitely revisit.
However, the answer to my problem does not lie in them. You suggested putting @AppStorage higher in the view hierarchy, but that is the root of my problem. I have helper methods that *do not belong to any view* because they are shared by multiple, unrelated views. Attaching such a method to a view would solve the storage problem but make them a real pain to call, if that's even possible.
At this time I have them declared as plain functions (outside any class), though @rob-secondstage suggested they be added to a class and that @AppStorage may work there. In theory the raw use of UserDefaults would work around this for @AppStorage (though I could not get it to work) but that still leaves the question around @SceneStorage values.
The use case is quite simple. User sets a preference in a settings screen which is then used in calculations for multiple views. Rather than repeat the calculations across multiple views, the code is factored out into helper methods, which need access to the preference values. The only "logical" way I have found so far is to pass in the preference values every time I call the helper functions but that is a kind of unnecessary handling as the views themselves don't actually need the raw preference value, only the result of the calculation.
Post
Replies
Boosts
Views
Activity
I didn't think it worked outside Views at all? Maybe I'm doing something different (wrong?). In my ContentView.swift (from the standard Xcode template), I have my ContentView struct defined as a TabView containing three other views. all also defined in the same file, along with a bunch of enums and some standalone functions outside of any struct/class/enum. I cannot declare an @AppStorage property in one of those functions. It gives me the error Property wrappers are not yet supported on local properties.
From what you're saying @rob-secondstage, by declaring these functions inside a helper class or struct, I could declare the wrapper at the class/struct level and thus use it in all of the member functions?
I figured out a bit of a hack to achieve this. For the Text views, I've embedded each in a ZStack where the first element is this:
Text(labelFiller).foregroundColor(.init(white: 1.0, opacity: 0.0))
The labelFiller variable is a String with suitable text that is the width of the widest possible value for any of my actual Text views that sit on top. By including the same invisible text on all rows, the sliders all line up, and this will adapt to Dynamic Type and system theme changes.
For those wanting to experiment easily, here's my current layout (though my fStop text is in reality more complex with helper functions):
List {
HStack(alignment: .center) {
Image(systemName: "camera.aperture")
.imageScale(.large)
.padding(.horizontal)
Slider(value: $fStop, in: 0...13)
Text("\(Int(fStop))")
.padding(.horizontal)
}
HStack(alignment: .center) {
Image(systemName: "circle.tophalf.fill")
.imageScale(.large)
.padding(.horizontal)
Slider(value: $focalLength, in: 15...600)
Text("\(Int(focalLength))")
.padding(.horizontal)
}
}