I have a private variable in a struct which I can only access using a setter and getter. I want to change this variable using a slider, so I am attempting to bind a different var with this var using willSet
:
struct MyStruct {
private var myVar: Float? = nil
mutating func setMyVar(newVal: Float) {
if (SomeCondition) { // always true when the slider is in use
myVar = newVal
} else {
// stuff
}
}
func getMyVar() -> Float {
myVar == nil ? 0.0 : myVar!
}
}
struct MyView: View {
@State var myStructToEdit = MyStruct()
@State var tempVar: Double = 0.0 {
willSet {
myStructToEdit.setMyVar(newVal: Float(newValue))
}
}
var body: some View {
VStack {
Text(String(tempVar))
Text(String(myStructToEdit.getMyVar()))
Slider(value: $tempVar, in: 1.0...20.0, step: 1.0)
}
}
}
As the slider moves, tempVar
changes but MyVar
doesn't. What is the correct way to achieve this binding?
CodePudding user response:
Property observers won't work with SwiftUI @State
variables.
Use .onChange(of:)
to act upon changes to tempVar
:
struct MyView: View {
@State var myStructToEdit = MyStruct()
@State var tempVar: Double = 0.0
var body: some View {
VStack {
Text(String(tempVar))
Text(String(myStructToEdit.getMyVar()))
Slider(value: $tempVar, in: 1.0...20.0, step: 1.0)
.onChange(of: tempVar) { value in
myStructToEdit.setMyVar(newVal: Float(value))
}
}
}
}
Use Binding(get:set:)
to directly set
and get
the value in your struct
:
You don't need tempVar
. You can directly set
and get
the value to and from your struct
.
struct ContentView: View {
@State var myStructToEdit = MyStruct()
var body: some View {
VStack {
Text(String(myStructToEdit.getMyVar()))
Slider(value: Binding(get: {
myStructToEdit.getMyVar()
}, set: { value in
myStructToEdit.setMyVar(newVal: value)
}), in: 1.0...20.0, step: 1.0)
}
}
}
or assign the Binding
to a let
to make it cleaner:
struct ContentView: View {
@State var myStructToEdit = MyStruct()
var body: some View {
let myVarBinding = Binding(
get: { myStructToEdit.getMyVar() },
set: { value in myStructToEdit.setMyVar(newVal: value) }
)
VStack {
Text(String(myStructToEdit.getMyVar()))
Slider(value: myVarBinding, in: 1.0...20.0, step: 1.0)
}
}
}
Note: Since myVarBinding
is already a binding, you do not need to use a $
to turn it into a binding.