State Wrapper Potential Bug?

Hi guys. I wanted to create a simple grid, but the view does not update after changing the value of "columns".
I guess the @State wrapper doesn't work as expected, even though the value gets changed.
The snippet of code is simplified to be more readable.
The purpose of the snippet: It must change and display a different number of columns depending on the number, however it always displays the default number.

I feel like the answer is easy, but I'd like to comprehend the principle.

struct ContentView: View {
    
    @State private var columns: Int = 4
    
    var body: some View {
        VStack{
            Text("Number of columns: \(columns)")
            HStack{
                ForEach(0..<columns){ column in
                    RoundedRectangle(cornerRadius: 1)
                        .frame(maxWidth: 1, maxHeight: .infinity)
                        .padding(10)
                }
            }
            Picker(selection: $columns, label: Text("Columns")) {
                ForEach(0..<10){ num in
                    Text("\(num)").tag(num)
                    
                }
            }
        }
    }
}

The error I get:

ForEach<Range, Int, ModifiedContent<ModifiedContent<RoundedRectangle, _FlexFrameLayout>, _PaddingLayout>> count (0) != its initial count (4). ForEach(_:content:) should only be used for constant data. Instead conform data to Identifiable or use ForEach(_:id:content:) and provide an explicit id!

However if I run the code below I get the same error.

struct ContentView: View {

@State private var columns: Int = 4
let myArray: [Int] = Array(0...7)
  var body: some View {
        VStack{
            Text("Number of columns: \(columns)")
            HStack{
                ForEach(0..<columns){ column in
                    RoundedRectangle(cornerRadius: 1)
                        .frame(maxWidth: 1, maxHeight: .infinity)
                        .padding(10)
                }
            }
            Picker(selection: $columns, label: Text("Columns")) {
                
                ForEach(myArray, id: \.self){ index in
                    Text("\(myArray[index])").tag(myArray[index])
                    
                }
            }
        }
    }
}

Thanks for your time.

It's a little strange but that specific ForEach initialiser — that takes a Range of Int — does not participate in the usual dynamic update system. It is only to be used with a constant range (like 0..<4, or 0..<count — where count is a let constant — etc). If you want to use ForEach with data that can change over time, you need to use the ForEach(_:id:) initialiser — so ForEach(0..<columns, id: \.self) is what you are looking for here.

1 Like

Thanks, I should have guessed on my own :sweat_smile:

Terms of Service

Privacy Policy

Cookie Policy