I am fairly new to iOS development. I am trying to update the property "cars" in the "Sire" model using a stepper. Whenever I press on or - from the stepper controls, it changes the value by a step and then becomes disabled.
If I bind the stepper to the variable cars, it works flawlessly.
struct AddSireView: View {
// @EnvironmentObject var sireVM:SiresViewModel
@State var newSire = Sire (id:"", name: "", ownerID: 0, info:"", achievments: "", cars: 0, cups: 0)
@State var cars = 0
@State var cups = 0
@State private var state = FormState.idle
var createAction: CreateAction
// TODO: Put validation that the added sire is valid and if not show errors to the user
var body: some View {
Form {
VStack (spacing: 18) {
TitledTextView(text: $newSire.name, placeHolder: "الاسم", title: "الاسم")
TiltedTextEditor(text: Binding<String>($newSire.info)!, title: "معلومات البعير")
TiltedTextEditor(text: Binding<String>($newSire.achievments)!, title: "انجازات البعير")
}
Stepper(value: $newSire.cars, in: 0...10,step:1) {
HStack {
Text ("سيارات:")
TextField("Cars", value: $newSire.cars, formatter: NumberFormatter.decimal)
}
}
And this is the "Sire" struct
struct Sire: Hashable, Identifiable, Decodable {
static func == (lhs: Sire, rhs: Sire) -> Bool {
lhs.id == rhs.id && lhs.name == rhs.name && lhs.ownerID == rhs.ownerID
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
hasher.combine(name)
hasher.combine(ownerID)
}
var id:String
var name:String
var ownerID:Int
var fatherID:String?
var info:String?
var achievments:String?
var cars:Int = 0
var cups:Int = 0
init (id:String, name:String, ownerID:Int, info:String? = nil, achievments:String? = nil,
fatherID:String? = nil, cars:Int = 0, cups:Int = 0) {
self.id = id
self.name = name
self.ownerID = ownerID
self.cars = cars
self.cups = cups
self.info = info
self.achievments = achievments
}
}
"Sire" was a class and i made it a Struct thinking that that was the problem, but to no avail.
CodePudding user response:
Consider this approach using an ObservableObject to hold your Sire. This allows you to use
both the Stepper and the Textfield at the same time.
struct ContentView: View {
@StateObject var sireModel = SireModel() // <-- here
var body: some View {
Form {
Stepper(value: $sireModel.sire.cars, in: 0...10, step:1) {
HStack {
Text ("سيارات: ")
TextField("", value: $sireModel.sire.cars, formatter: NumberFormatter())
}
}
}
}
}
class SireModel: ObservableObject {
@Published var sire: Sire = Sire(id:"", name: "", ownerID: 0, info:"", achievments: "", cars: 0, cups: 0)
}
CodePudding user response:
Get rid of the custom implementations for Equatable and Hashable (func == and func hash) you don't include cars in it so SwiftUI doesn't know when to reload.
SwiftUI is all about identity if you change how Swift computes the identity (using Hashable, Equatable and Identifiable) you change the behavior.
The video above is the "best" place to learn about the concept.

