@Published not updating UI on changing value of viewmodel

1.4k Views Asked by At

In my ViewController (UIHostingController) i have viewModel (reference type) shared between ViewController and its rootView. And viewModel has one property which is wrapped as @Published.

  1. On receving response to viewcontroller from api call.
  2. updating viewModel with received data from server
  3. here after setting value to @Published it is not updating the UI

ViewController Code:

final class DashboardSceneViewController: UIHostingController<DashboardSceneView> {
    var viewModel: DashboardSceneViewModel?
    func setVm(response : Model){
        viewModel.data = response. ///Here it should update DashboardSceneView But not updating
    }
}

ViewModel:

protocol DashboardSceneViewModel   {
    var delegate: DashboardSceneViewDelegate? { get set }
    var homeJson : HomeModel? {get set}
}


class DefaultDashboardSceneViewModel: DashboardSceneViewModel{
    @Published var homeJson: Model?
}

View:

//Not getting redrawn on change in @published property change
struct DashboardSceneView: View {
    var viewModel: DashboardSceneViewModel
    var body: some View {
        VStack {
            if viewModel.homeJson != nil {
                Text(viewModel.homeJson?.header ?? "")
            }
            Button("Tap"){
                print()
            }
        }
    }
}
2

There are 2 best solutions below

0
On BEST ANSWER

@Published does not update SwiftUI view by itself.

Your view model should be

  1. is-a ObservableObject, and
  2. view model property wrapped into @ObservedObject in view

See this one for similar scenario with observable protocol https://stackoverflow.com/a/59504489/12299030

0
On

In order for @Published to update the UI, it's parent(DefaultDashboardSceneViewModel) should be conform to ObservableObject:

protocol DashboardSceneViewModel: ObservableObject {

Now, for ObservableObject to bind to your View, you need to mark it with @StateObject. However, since DashboardSceneView did not initialize viewModel you mark it with @ObservedObject:

@ObservedObject var viewModel: DashboardSceneViewModel