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){_ inHStack(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.
Best Answer
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 = 0var body: some View {VStack {ForEach(0 ..< counter, id:\.self) { i inText("row: \(i.description)")}Button(action: {self.counter += 1}, label: {Text("counter \(counter.description)")})}}}
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){_ inHStack(spacing: 0){//here comes my view}}.id(s_countVenues)
I have silenced it with ', id: .self'