TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SOLVED: increment an integer in a ForEach loop

Forums > SwiftUI

So another "why is this hard" question:

I have a fairly simple grid layout:

struct ContentView: View {
    @State var gridSize = 3
    @State var selected = 0
    @State var aCount = 0

    var body: some View {

        Grid (horizontalSpacing: 0, verticalSpacing: 0) {
            ForEach(0..<gridSize, id: \.self) { row in
                GridRow{
                    ForEach(0..<gridSize, id: \.self) { col in
                        Rectangle()
                            .foregroundColor(.gray)
                            .overlay(Text("\(aCount)"))
                            .border(Color.black)
                            .bold()
                    }
                }
            }
        }
    }

}

This creates a grid of gridSize x gridsize grey rectangles, so 3x3 in this version

and in a class file I have a fairly simple function that increments an int passed to it by 1 and returns that new value:

func theIncrement(theCount: Int) -> Int {
    let theCounter = theCount + 1
    return theCounter
}

how do use that function to increment aCount in the inner foreach loop? This does not seem like it should be impossible, and yet, swiftUI is being itself again.

any help is appreciated

2      

Since you have it marked as an @State property, every time you increment aCount, your View with redraw. Probably not what you want to do in a loop that is just populating the screen.

Instead, in your View's initializer you could create an array that has a length of gridSize * gridSize (call it, say, matrix or whatever), fill it with your values you want to display, and then inside the inner ForEach, you can access the values like so:

Rectangle()
    .foregroundColor(.gray)
    .overlay(Text("\(matrix[(row * gridSize) + col])"))
    .border(Color.black)
    .bold()

2      

I was think same thing as @roosterboy but changing the ForEach

struct ContentView: View {
    @State var gridSize = 3

    var body: some View {
        Grid (horizontalSpacing: 0, verticalSpacing: 0) {
            ForEach(0..<gridSize, id: \.self) { row in 
                GridRow{
                    ForEach(1...gridSize, id: \.self) { col in // <- change to start at one to the gridsize
                        Rectangle()
                            .foregroundColor(.gray)
                            .overlay(Text("\(col + (row * gridSize))")) // <- add column count to the row count times grid size
                            .border(Color.black)
                            .bold()
                    }
                }
            }
        }
    }
}

2      

Okay I get how to build a grid. That's easy. But what I need the counter for is so that eventually I can have button 1,1, when clicked, kick off a function that checks the states of buttons 1,2 and 1,0 and take action on those.

I have tried literally everything i can think of to do this, and the only thing I've come up with is an array of structs with the buttons in them, whcih I have, and I need to have the coutner so I can be sure of what button is where so that I know that button at 0,0 is also button[0] in the array.

i have been beating my head against this for over a month and have found zero information anywehre on how to have button a talk to and get state from buttons b and c. So this was the best thing I can manage.

SwiftUI is great for beginners until you want to move past drawing UIs and do more than click a button and pop an alert, or at least that's how i feel right now. In UIKit or even C#, this kind of thing is easy. I just want to do it in SwiftUI and I don't understand why this is hard.

2      

If I get you right then you want a button that does different action or takes from an array

struct ContentView: View {
    let gridSize = 3
    let array = [
        "index 0",
        "index 1",
        "index 2",
        "index 3",
        "index 4",
        "index 5",
        "index 6",
        "index 7",
        "index 8",
    ]

    var body: some View {
        Grid (horizontalSpacing: 0, verticalSpacing: 0) {
            ForEach(0..<gridSize, id: \.self) { row in
                GridRow{
                    ForEach(0..<gridSize, id: \.self) { col in
                        let buttonNumber = col + (row * gridSize)
                        Button {
                            // THIS WILL TAKE AN INDEX NUMBER AND PRINT WHAT IN THE ARRAY
                            guard buttonNumber < array.count else { return }
                            print(array[buttonNumber])

                            // THIS WILL GO TO A METHOD TO RUN SOME OTHER CODE
                            getButtonTapped(for: buttonNumber)
                        } label: {
                            Rectangle()
                        }
                        .foregroundColor(.gray)
                        .overlay(Text("\(buttonNumber)"))
                        .border(Color.black)
                        .bold()
                    }
                }
            }
        }
    }

    func getButtonTapped(for number: Int) {
        switch number {
        case 0:
            print("Do something for number 0")
        case 1:
            print("Do something for number 1")
        case 2:
            print("Do something for number 2")
        case 3:
            print("Do something for number 3")
        case 4:
            print("Do something for number 4")
        case 5:
            print("Do something for number 5")
        case 6:
            print("Do something for number 6")
        case 7:
            print("Do something for number 7")
        case 8:
            print("Do something for number 8")
        default:
            break
        }
    }
}

2      

@NigelGee OMG, that's like 80% of what I've been losing my MIND on.

I can actually now tell what button i'm clicking from WITHIN THE BUTTON

okay, so my next question: i click button 1, but I want that to change the overlay for button say...4, how would I do that?

2      

Change the oveylay modifiler (in this example) to .overlay(Text("\(array[buttonNumber])")) then in the method change case 1 to array[4] = "changed"

struct ContentView: View {
    let gridSize = 3

    @State private var array = [
        "button 0",
        "button 1",
        "button 2",
        "button 3",
        "button 4",
        "button 5",
        "button 6",
        "button 7",
        "button 8",
    ]

    var body: some View {
        Grid (horizontalSpacing: 0, verticalSpacing: 0) {
            ForEach(0..<gridSize, id: \.self) { row in
                GridRow{
                    ForEach(0..<gridSize, id: \.self) { col in
                        let buttonNumber = col + (row * gridSize)
                        Button {
                            getButtonTapped(for: buttonNumber)
                        } label: {
                            Rectangle()
                        }
                        .foregroundColor(.gray)
                        .overlay(Text(array[buttonNumber]))
                        .border(Color.black)
                        .bold()
                    }
                }
            }
        }
    }

    func getButtonTapped(for number: Int) {
        switch number {
        case 0:
            print("Do something for number 1")
        case 1:
            array[4] = "CHANGED"
        case 2:
            print("Do something for number 2")
        case 3:
            print("Do something for number 3")
        case 4:
            print("Do something for number 4")
        case 5:
            print("Do something for number 5")
        case 6:
            print("Do something for number 6")
        case 7:
            print("Do something for number 7")
        case 8:
            print("Do something for number 8")
        default:
            fatalError("No action assigned for buttons after nine")
        }
    }
}

Note: Change the arrat to be @State as it now look for changes

2      

Oh wow, that works really well.

like thank you SO much, I think I have a good shot at getting this to work now!

2      

Hacking with Swift is sponsored by String Catalog.

SPONSORED Get accurate app localizations in minutes using AI. Choose your languages & receive translations for 40+ markets!

Localize My App

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.