Reputation: 8517
I am storing a Int value as State in my View. When I press a button the Int increase by one. This is working fine when I print my int value.
I have now a ForEach loop, which iterates based on this Int. When I set my State on 2 by default it works fine at the beginning. However, when I increase that Int my ForEach is not called again.
I understand that State will reload my actual view. Does it only load specific parts?
Here I declare my State:
@State var s_countVenues : Int = 2
This is the ForEach I use. It works at the beginning, however changing s_countVenues
does NOT update the view.
ForEach(0..<self.s_countVenues)
{_ in
HStack(spacing: 0)
{
//here comes my view
}
}
If necessary, here I am increasing my value by one. It works, I printed the changes and if I use it inside a Label, the Label gets updated.
self.s_countVenues += 1
TL:DR:
My Int State is working. I can increase and print it inside a label. However, using it as Statement in ForEach does not call that loop again after changing.
Upvotes: 20
Views: 22948
Reputation: 257493
It is not due to state, it is because you use ForEach
constructor with constant Range
, it is documented feature, so not supposed to update, so it is not updated. The simplest solution is as following - to use identifier joined to your state. It just indicates for rendering engine that ForEach is new so refresh (Tested with Xcode 11.2 / iOS 13.2)
ForEach(0..<self.s_countVenues)
{_ in
HStack(spacing: 0)
{
//here comes my view
}
}.id(s_countVenues)
Upvotes: 7
Reputation: 17534
from apple docs
extension ForEach where Data == Range<Int>, ID == Int, Content : View {
/// Creates an instance that computes views on demand over a *constant*
/// range.
///
/// This instance only reads the initial value of `data` and so it does not
/// need to identify views across updates.
///
/// To compute views on demand over a dynamic range use
/// `ForEach(_:id:content:)`.
public init(_ data: Range<Int>, @ViewBuilder content: @escaping (Int) -> Content)
}
So, you have to use (as suggested by Apple)
struct ContentView: View {
@State var counter = 0
var body: some View {
VStack {
ForEach(0 ..< counter, id:\.self) { i in
Text("row: \(i.description)")
}
Button(action: {
self.counter += 1
}, label: {
Text("counter \(counter.description)")
})
}
}
}
Upvotes: 54