Combine link UIViewController to @Published

I've set up a nice little view model with an @Published state:

class ViewModel {
    @Published private(set) var state = State.loading
    private var cancellable: Set<AnyCancellable> = []
    enum State {
        case data([Users.UserData])
        case failure(Error)
        case loading
    }
}

I've then linked to this in my UIViewController's viewDidLoad function:

private var cancellable: AnyCancellable?

override func viewDidLoad() {
    super.viewDidLoad()
    cancellable = viewModel.$state.sink{  [weak self] _ in
        DispatchQueue.main.async {
           self?.render()
        }
    }
}

however, when I link directly to the state it doesn't change when the state is changed from the view model (not shown in the code).

    private func render() {
        switch viewModel.state {
        case .loading:
            // Show loading spinner
            print("loading render")
        case .failure(let error):
            // Show error view
            print("failing render")
        case .data(let userData):
            // Show user's profile
            self.applySnapshot(userData: userData)

            print("loaded \(userData) render")
        }
    }

Now I can pass the state from my viewDidLoad, but how can I link directly to the viewModel state using Combine and UIKit?


Make sure your ViewModel conforms to ObservableObject like so: class ViewModel: ObservableObject. This way it knows to react to changes, despite being a UIViewController.