hi,
i admit to being confounded by these types of things as well, but i'll give it a try.
when you use GridView, the environment object is a Grid, which publishes any changes to its squares array. you make a direct change to the squares array in the grid, so it publishes the change and GridView can see that change.
when you use PuzzleView, the environment is a Puzzle that publishes any changes to its grid. you make a direct change to the squares array in the grid (which does, indeed, change), so it publishes the change and ... who can see that? who is listening? no view is subscribed to it.
this is where Combine comes in to play, so that a PuzzleView can subscribe to changes in the squares of the Grid. admittedly, i struggle with real Combine code; but the code below does solve the problem by making sure that when a Puzzle makes a change to one of the Squares of its Grid, the Puzzle broadcasts that change. (this is both a poor-man's avoidance of real Combine code, and not liking to reach deep inside an object with syntax such as puzzle.griddy.squares[0][0] = Square(letter:"!")
)
class Square {
var letter: String
init(letter: String){
self.letter = letter
}
}
class Grid : ObservableObject {
var squares:[[Square]] = [
[Square(letter: "A"), Square(letter: "B"), Square(letter: "C")],
[Square(letter: "D"), Square(letter: "E"), Square(letter: "F"), ]
]
func updateSquare(row: Int, col: Int, newLetter: String) {
squares[row][col].letter = newLetter
}
}
class Puzzle: ObservableObject {
var grid: Grid = Grid()
func updateSquare(row: Int, col: Int, newLetter: String) {
objectWillChange.send()
grid.updateSquare(row: row, col: col, newLetter: newLetter)
}
}
struct PuzzleView: View {
@EnvironmentObject var puzzle: Puzzle
var body: some View {
VStack {
Text("\(puzzle.grid.squares[0][0].letter)")
Button("Change Numbers"){
puzzle.updateSquare(row: 0, col: 0, newLetter: "!")
}
}
}
}
hope that helps,
DMG