0

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?

2
  • 1
    "Do I need to make an instance of my model class within the view file?" Yes -- look up @StateObject and @ObservedObject (the Apple SwiftUI tutorials might be a good place to start). You haven't actually shown any code that updates a quantity, but those property wrappers I mentioned will be the key to getting it to work when you do have some code that mutates the item. Commented Apr 5, 2022 at 4:14
  • 1
    Global variables like you have defined metzScissor don't work as you are expecting. SwiftUI requires its wrappers so it knows when to reload the View, @StateObject is used to initialize and @ObservedObject and @EnvironmentObject are used in the children. Commented Apr 5, 2022 at 12:53

1 Answer 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)
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.