3

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()
            }
        }
    }
}
Timmy
  • 4,098
  • 2
  • 14
  • 34
user968597
  • 1,164
  • 2
  • 15
  • 30
  • we don't use view model objects in SwiftUI, you have to learn `@State` and `@Binding`. For api call use `.task { state = await download() }` – malhal Aug 05 '22 at 13:52

2 Answers2

1

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
Timmy
  • 4,098
  • 2
  • 14
  • 34
1

@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

Asperi
  • 228,894
  • 20
  • 464
  • 690