'Noob Swift UI question - Updating views from model class

I have my ItemModel and my Contentview, but when run the program the view doesn't update with the new quantity in real time. How do I get the model and the view to "talk"

import Foundation
import SwiftUI

class Item: ObservableObject {
    var name: String
    @Published var qty: Int
    

    init(name: String, qty: Int) {
        self.name = name
        self.qty = qty
    }
    
}

var metzScissor = Item(name: "Metz Scissor", qty: 5)
import SwiftUI

struct ContentView: View {
    
    var body: some View {
        
        NavigationView {
        
        VStack {
            Text("Items In Stock")
                .font(.title)
                .padding()
            Spacer()
            NavigationLink (
                destination: ItemDetailView(),
             label: {
                 Text(metzScissor.name)
            })
            Spacer()
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Do I need to make an instance of my model class within the view file?



Solution 1:[1]

Normally the ObservableObject that holds your model structs in @Published properties is a singleton that you pass into the View struct hierarchy using the environmentObject modifier in the body of the App struct. This makes it available in ContentView and every View below and body will run when the model structs change if you declare an @EnvironmentObject var.

The reason it’s a singleton is that you can have a different singleton containing sample data to use when previewing. The reason we don’t use @StateObject is that is not init during previewing and you usually don’t need the App struct body to be recomputed when the model struct changes.

Perhaps something like this:

import SwiftUI

struct Item: Identifiable {
    let id = UUID()
    var name: String
    var qty: Int
    
    init(name: String, qty: Int) {
        self.name = name
        self.qty = qty
    }
}

class Model: ObservableObject {
    @Published items: [Item] = []

    static let shared = Model()

    static let preview: Model = {
        let metzScissor = Item(name: "Metz Scissor", qty: 5)
        return Model(items:[metzScissor])
    }()
}
import SwiftUI
@main
struct TestApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(Model.shared)
        }
    }
}
import SwiftUI

struct ContentView: View {
    @EnvironmentObject var model: Model

    var body: some View { 
        NavigationView {
            List{
                ForEach(model.items) item in
                 NavigationLink (
                    destination: ItemView(item: item),
                 label: {
                     Text(item.name)
                })
            }
            .navigationTitle("Items in Stock")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
        .environmentObject(Model.preview)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1