I am working on a simple Reversi app built using SwiftUI. Recently I was updating my app and noticed a bug with the UI not updating to match the game state.
Here is a screenshot of an in-progress game:
Here is a screenshot of the board after I press the undo button:
In the second screenshot, the middle-rightmost white piece should be black. The views that display the pieces depend on a game
environmentObject
:
class Game: ObservableObject {
@Published var board = Board()
@Published var times = GameState.times
var pieces: [Piece] {
board.pieces.filter({ $0 != nil}) as! [Piece]
}
}
I only ever initialize a Game()
object once, in the root of my app:
@main
struct DuelingDisksApp: App {
@StateObject private var game = Game()
var body: some Scene {
WindowGroup {
GamesView()
.environmentObject(game)
}
}
}
Later, I use the game
in a view which displays the correct piece (if any) for a square:
struct SquareView: View {
@EnvironmentObject private var game: Game
let column: Int
let row: Int
var body: some View {
let square = Square(column: column, row: row)
let animation: Animation = .linear(duration: 0.3)
ZStack {
Button {
} label: {
Text("")
}
.disabled(game.board.gameOver)
if let piece = game.board.pieces[square] {
PieceView(isLight: piece.isLight)
.frame(width: boardLength / 16, height: boardLength / 16)
.transition(.opacity.animation(animation))
.animation(animation, value: game.board)
.zIndex(1)
}
}
}
}
Any ideas as to why only some of the views are getting updated? One thing I tried was to replace @Published var board = Board()
in the Game
class with:
@Published var board = Board() {
willSet {
objectWillChange.send()
}
}
This fixed the issue. My understanding was that this is equivalent to @Published var board = Board()
. If anyone has any ideas on why this issue might be occurring and why adding the objectWillChange
fixes it, I would love to know. From all my testing I have been wondering if it is a bug with SwiftUI but want to make sure that I'm not just doing something incorrectly.
Thanks for any help!