How to pass data from a parent model class to a subview in SwiftUI

Viewed 577

I am having my main view in ContentView class and I do the network call in ContentViewModel class and update a class call User with the response.

My ContentView has several subviews such as HeaderView. When I update the User class properties from the API response, I want to update UI elements defined in HeaderView as well. How can I pass data to my subview (HeaderView) from the ContentViewModel class?


I can update the ContentView elements which is pretty simple by setting the ContentViewModel class ObservableObject

class ContentViewModel: ObservableObject {

and Published the User object

@Published var user = User()

and update the attribute of user once I received the API response in the same ContentViewModel

self.user.name = name

where my ContentView has the relationship with it's model class like below

@StateObject private var contentViewModel = ContentViewModel()

and the UI updates as follow

Text("My name \(contentViewModel.user.name)")

That is the working scenario for ContentView. But I need to pass the value to HeaderView(). My user class is like below

import Foundation

class User {
    var name = ""
// more attributes
}
2 Answers

this is the pattern I often use: (note no private var)

struct ContentView: View {
    @StateObject var contentViewModel = ContentViewModel()
    ...
    var body: some View {
        ...
        HeaderView(contentViewModel: contentViewModel)
    }
}

struct HeaderView: View {
    @ObservedObject var contentViewModel: ContentViewModel

    var body: some View {
        ...
        Text("My name \(contentViewModel.user.name)")
    }
}

struct User {
    var name = ""
// more attributes
}

You can use the same idea with the ".environment(...)" pattern to pass ContentViewModel to all subviews.

Edit: as suggested by @Asperi User should be made a struct.

When I update the User class properties from the API response, I want to update UI

Independently of how do you pass your model to sub-view it will not update because your User is-a class, so changing its properties will not activate publishing (because published wrapper holds a reference to User which is not changed) and so view not updating.

Instead you should make User a struct

struct User {
    var name = ""
// more attributes
}

or make it ObservableObject as well with all needed properties published and pass by reference to subview observing it in regular way.

Related