Specific question:
SwiftUI doesn't like us initializing @State
using parameters from the parent, but what if the parent holding that @State
causes major performance issues?
Example:
How do I make tapping on the top text change the slider to full/empty?

Dragging the slider correctly communicates upwards when the slider changes from full to empty, but tapping the [Overview] full:
text doesn't communicate downwards that the slider should change to full/empty.
I could store the underlying Double
in the parent view, but it causes major lag and seems unnecessary.
import SwiftUI
// Top level View. It doesn't know anything about specific slider percentages,
// it only knows if the slider got moved to full/empty
struct SliderOverviewView: View {
// Try setting this to true and rerunning.. It DOES work here?!
@State var overview = OverviewModel(state: .empty)
var body: some View {
VStack {
Text("[Overview] full: \(overview.state.rawValue)")
.onTapGesture { // BROKEN: should update child..
switch overview.state {
case .full, .between: overview.state = .empty
case .empty: overview.state = .full
}
}
SliderDetailView(overview: $overview)
}
}
}
// Bottom level View. It knows about specific slider percentages and only
// communicates upwards when percentage goes to 0% or 100%.
struct SliderDetailView: View {
@State var details: DetailModel
init(overview: Binding<OverviewModel>) {
details = DetailModel(overview: overview)
}
var body: some View {
VStack {
Text("[Detail] percentFull: \(details.percentFull)")
Slider(value: $details.percentFull)
.padding(.horizontal, 48)
}
}
}
// Top level model that only knows if slider went to 0% or 100%
struct OverviewModel {
var state: OverviewState
enum OverviewState: String {
case empty
case between
case full
}
}
// Lower level model that knows full slider percentage
struct DetailModel {
@Binding var overview: OverviewModel
var percentFull: Double {
didSet {
if percentFull == 0 {
overview.state = .empty
} else if percentFull == 1 {
overview.state = .full
} else {
overview.state = .between
}
}
}
init(overview: Binding<OverviewModel>) {
_overview = overview
// set inital percent
switch overview.state.wrappedValue {
case .empty:
percentFull = 0.0
case .between:
percentFull = 0.5
case .full:
percentFull = 1.0
}
}
}
struct SliderOverviewView_Previews: PreviewProvider {
static var previews: some View {
SliderOverviewView()
}
}
Why don't I just store percentFull
in the OverviewModel
?
I'm looking for a pattern so my top level @State
struct doesn't need to know EVERY low level detail specific to certain Views.
Running the code example is the clearest way to see my problem.
This question uses a contrived example where an Overview
only knows if the slider is full
or empty
, but the Detail
knows what percentFull
the slider actually is. The Detail
has very detailed control and knowledge of the slider, and only communicates upwards to the Overview
when the slider is 0%
or 100%
What's my specific case for why I need to do this?
For those curious, my app is running into performance issues because I have several gestures that give the user control over progress. I want my top level ViewModel
to store if the gesture is complete or not, but it doesn't need to know the specifics of how far the user has swiped. I'm trying to hide this specific progress Double
from my higher level ViewModel
to improve app performance.