Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI observe published object of published object

When hitting the button, a player is added to the game and I want to observe the changes in the game through the view model. When I hit the button, the counter doesn't change.

It's almost as if I need the game within the ContentViewModel to be both @ObservedObject and @Published.

Can someone help me understand the fundamentals of why this is setup wrong and how I can fix it?

import SwiftUI
import Combine

class Game: ObservableObject {
    @Published var players: [String] = []

    func addPlayer(_ player: String) {
        players.append(player)
    }
}

class ContentViewModel: ObservableObject {
    @Published var game: Game {
        didSet {
            subscription = game.objectWillChange.sink { [weak self] _ in
                self?.objectWillChange.send()
            }
        }
    }
    var subscription: AnyCancellable?

    init(game: Game) {
        self.game = game
    }
}

struct ContentView: View {
    @ObservedObject var viewModel: ContentViewModel

    var body: some View {
        Text("Num players: \(viewModel.game.players.count)")
            .padding()

        Button("Add player") {
            viewModel.game.addPlayer("player")
        }
    }
}
like image 683
Shawn Avatar asked Sep 05 '25 03:09

Shawn


1 Answers

You want to set the subscription in the init. This will make sure that every time the game object instance changes, you will trigger ContentViewModel to change as well.

Your code doesn't work because only the object instance is mutating - not the object reference. So game won't trigger the didSet, therefore you will never set subscription.

Code:

class ContentViewModel: ObservableObject {
    @Published var game: Game
    var subscription: AnyCancellable?

    init(game: Game) {
        self.game = game

        subscription = game.objectWillChange.sink { [weak self] _ in
            self?.objectWillChange.send()
        }
    }
}
like image 116
George Avatar answered Sep 07 '25 20:09

George