0
votes

I am trying to use forEach in HStack and VStack. I am using Text in them and Text is not appearing while running but onAppear print values. Please have a look on my code. Why Text is not appearing? How can I make this work?

@State var sd = ["1","2","3","4","5","6","7"]

VStack {
    ForEach(0...sd.count/3) { _ in
        HStack {
            ForEach(0...2) { _ in
                if(self.sd.isEmpty) {
                } else {
                    Text("Test")
                        .onAppear() {
                            if(!self.sd.isEmpty) {
                                print("i appeared")
                                self.sd.removeFirst()
                            }
                    }
                }
            }
            Spacer()
        }
    }
}

What I am trying to achieve here?

I am trying to create a HStacks with maximum 3 Texts in it. I am using array here only to rendered Text 7 times.

Expected result with array with 7 elements--->

Want to create a VStack of 3 HStacks, In first 2 HStacks I want to render Text 3 times and in last HStack I want only one Text. (Like I have 7 array elements that's why 3 texts in first two hstacks and one in last hstack). If array has 10 elements, then 3 Hstacks of 3 Texts and last Stack with 1 Text. I am unable to render Text because my array is @state var and it refresh view.body every time I remove firstElement from it.

Is there any way to achieve this behaviour I am trying to achieve by using SwiftUI only. I don't want to use UICollection view.

1
Three quick questions. (1) How many times is "i appeared" executing? (2) What are you trying to do with the nested ForEach loops? But mostly, (3) What is your expected output?dfd
1) Seven times. 2) I am trying to get 3 hstacks (first two with 3 texts and third with 2 texts). 3) 3 hstacks (first two with 3 texts and third with 2 texts).Lalli
Not to sound critical, but your array only has seven values. :-) More, you are treating a one-dimensional array like a two-dimensional one. (Usually inner loops work on a second dimension.) Sorry for repeating, but 3 Stacks containing 3, 3, and 2 Texts. What values?dfd
Yes my main question is that its printing "I appeared" but Texts are not visible in view. Answer below clarifies that why nothing is rendered. But I want to achieve 3 3 2 Hstacks. How can I do that?Lalli
Maybe, the problem is you're being too vague for me to help. From your comment to the answer, I'm wondering if it might help me if you talk in terms of UIKit. (I'm thinking your problem is with what Apple introduced last month but maybe it's deeper. Again - but this time specifically - what should each "stack" show? (It might be easier to show that in your question - formatting comments is rather poor.) Given your array of seven values, how should they be rendered?dfd

1 Answers

0
votes

You generally don't want to change a @State variable as a side-effect of the evaluation of body; in this case, your self.sd.removeFirst() is causing the body to be marked as needing to be re-evaluated, so SwiftUI just keeps calling it until your sd array is empty, which is why you don't see anything being rendered.

To get the effect you want, this is one way you can do it:

import SwiftUI

struct ContentView : View {
    @State private var sd = ["1","2","3","4","5","6","7"]
    private let columns = 3

    var body: some View {
        VStack {
            ForEach(Array(stride(from: 0, to: sd.count, by: columns))) { row in
                HStack {
                    ForEach(0..<self.columns) { col in
                        if row + col < self.sd.count {
                            Text("\(self.sd[row + col])")
                        }
                    }
                }
            }
        }
    }
}

P.S. Most attempts to modify state within the body evaluation seem to result in the runtime warning Modifying state during view update, this will cause undefined behavior. – it seems that your array mutation somehow side-stepped this check, but hopefully that sort of thing will be called out at runtime in the future.