swiftuionchangepicker

Picker selection not updating the view


In my app there is a view with several pickers. If I select a value with one of them ($limits[index].from), a value that depends on it should be updated. Unfortunately, this does not work. Only when I select the desired value a second time is the dependent value (limits[index + 1].to) also displayed correctly.

Here's my code:

import SwiftUI

class Limit: Identifiable {
   var value: Int
   var from: Double
   var to: Double

   init(value: Int, from: Double, to: Double) {
      self.value = value
      self.from = from
      self.to = to
   }
}

struct ContentView: View {

   @State private var limits: [Limit] = [
      Limit(value: 1, from: 10.5, to: 12),
      Limit(value: 2, from: 8.5, to: 10),
      Limit(value: 3, from: 6.5, to: 8),
      Limit(value: 4, from: 4.5, to: 6),
      Limit(value: 5, from: 2.5, to: 4),
      Limit(value: 6, from: 0, to: 2)
   ]
   private var sum:Double = 12

   var body: some View {
      VStack {
         ForEach(0..<limits.count, id: \.self) { index in
            HStack {
               Text("Value \(limits[index].value): ")
               Text("\(limits[index].to, specifier: "%.1f")")
               Text("   - ")
                
               let values = getChangeValues(limit: limits[index])
                
               Picker("from", selection: $limits[index].from) {
                  ForEach(values, id: \.self) { value in
                     Text("\(value, specifier: "%.1f")").tag(value)
                  }
               }
               .onChange(of: limits[index].from) {
                  limits[index + 1].to = limits[index].from - 0.5
               }
            }
         }
      }
      .padding()
   }

   private func getChangeValues(limit: Limit) -> [Double] {
      return Array(stride(from: limit.from - 0.5 * floor(sum / 6), through: limit.from + 0.5 * floor(sum / 6), by: 0.5))
   }
}

I don't know how to solve it.


Solution

  • The secret was to replace class with struct. Then everything worked as desired. Thanks to lorem ipsum!

    Here is the (slightly) adjusted code:

    struct Limit {
        var value: Int
        var from: Double
        var to: Double
        
        init(value: Int, from: Double, to: Double) {
            self.value = value
            self.from = from
            self.to = to
        }
    }