Weird Swiftui button behavior part 2

Okay, was able to create a much smaller repro.

ContentView.swift:

import SwiftUI

struct ContentView: View {
	@State var gridSize = 3
	@State var selected = 0
	@State var aCount = 0
	@State var theToggle = true
	var theTitle = "test"
	@State var buttonBlank: Bool = true

	var body: some View {
		@State var gridCellArr = buildStructArray(theGridSize: gridSize)
		HStack {
			Button {

			} label: {
				Text("Commit Move")
			}
			.disabled(buttonBlank)
		}
		Grid(horizontalSpacing: 0, verticalSpacing: 0) {
			ForEach(0..<gridSize, id: \.self) {
				row in
				GridRow {
					ForEach(0..<gridSize, id: \.self) { col in
						GeometryReader { proxy in
							let index = row * gridSize + col
							Button {
								var theTuple = doSomethingElseOnClick(for: gridCellArr[index].index, myArray: gridCellArr)
								
								gridCellArr[index].backCol = theTuple.myColor
								gridCellArr[index].title = theTuple.myTitle
							} label: {
								Text(gridCellArr[index].title)
									.font(.system(size: 36, weight: .heavy, design: .serif))
									.frame(width: proxy.frame(in: .global).width,height: proxy.frame(in: .global).height)

							}
							.background(gridCellArr[index].backCol)
							.border(Color.black)

							.onAppear(perform: {
								gridCellArr[index].xCoord = col
								gridCellArr[index].yCoord = row
							})
						}
					}
				}
			}
		}
	}
}

and the class + two other functions used:

import SwiftUI
import Foundation

@Observable  class Cell: Identifiable {
	let id = UUID()
	var title: String = ""
	var buttonToggled: Bool = false
	var index: Int = 0
	var xCoord: Int = 0
	var yCoord: Int = 0
	var backCol: Color = .gray
}

func buildStructArray(theGridSize: Int) -> [Cell] {
	var myStructArray: [Cell] = []
	let arraySize = (theGridSize * theGridSize) - 1
	for i in 0...arraySize {
		myStructArray.append(Cell())
	}

	for i in 0...arraySize {
		myStructArray[i].index = i
	}
	return myStructArray
}

func doSomethingElseOnClick(for myIndex: Int, myArray: [Cell]) -> (myColor: Color, myTitle: String, myCommitButtonStatus: Bool) {
	var theCommitButtonStatus: Bool = true
	switch myArray[myIndex].title {
		case "":
			myArray[myIndex].title = "S"
			theCommitButtonStatus = false
		case "S":
			myArray[myIndex].title = "O"
			theCommitButtonStatus = false
		case "O":
			myArray[myIndex].title = ""
			theCommitButtonStatus = true
		default:
			print("Something went wrong, try restarting the app")
	}


	if myArray[myIndex].title == "Button" {
		print("it's a button")
	}
	var theColor: Color
	if myIndex <= 7 {
		let testIndex = myIndex + 1
		print("\(myArray[testIndex].index)")
		theColor = Color.green
	} else {
		let testIndex = myIndex - 1
		print("\(myArray[testIndex].index)")
		theColor = Color.blue
	}

	let theReturnTuple = (myColor: theColor, myTitle: myArray[myIndex].title, myCommitButtonStatus: theCommitButtonStatus)
	return theReturnTuple
	//return theColor
}

same issue with this as before:

the idea is, the board is built, all cells have a title of "" (blank) and Commit Move is disabled:

  1. the first time a button is clicked, its title should change to S and commit move is enabled
  2. second click, title changes to O, commit move is still enabled
  3. third click, title changes to "", commit move is disabled.

So a three-click rotation: "", "S", "O".

What i'm actually getting is a four click rotation:

  1. first click, button doesn't visibly change, but it thinks the title is now "S" and the commit move button is enabled
  2. second click, Button does visibly change to "S", title is STILL "S", and the commit move button is enabled
  3. third click, button visibly changes to "O", title is "O" and the commit move button is enabled
  4. fourth click, button visibly changes to "", title is "" and the commit move button is disabled

That's the cycle, but it gets weirder.

suppose on button 0, i leave it at "S" or "O".

Then i click on button 1. I get:

  1. first click: button does visibly change to "S", title is "S", and the commit move button is enabled
  2. second click: button visibly changes to "O", title is "O" and the commit move button is enabled
  3. third click: BOTH buttons change to "", title for both is "" and the commit move button is disabled

if I keep clicking, it goes back to a four-click cycle

if I move the buttonBlank @state var underneath body, the "all buttons blank" problem goes away, it's a three click cycle as I expect, but buttonBlank never changes so the commit move button is always disabled.

i am absolutely sure it's related to how I manipulate buttonBlank, because even if I have a line in the grid button click action block that just reads buttonBlank = false or self.buttonBlank = false I get the same behavior.

i am absolutely confused as to why though.