skip to Main Content

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)
                    }
                }

enter image description here

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.

2

Answers


  1. 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)
     }
    
    Login or Signup to reply.
  2. 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.

    Check out Demystify SwiftUI

    The video above is the "best" place to learn about the concept.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search