I have a list of toppings to include on a pizza. Each item in the list is a struct:
struct Topping: Identifiable {
let name: String
let price: Double
@State var amount: Int
let id = UUID()
}
The list is created in a Class in file MenuDataService.swift, is defined using static let, then initialized in a ViewModel file:
//FILE MenuDataService.swift
Class MenuDataService {
static let toppingsList: [Topping] = [Topping(name: "Cheese", price: 3.00, amount: 0), Topping(name: "Sauce", price: 3.00, amount: 0)]
}
//FILE MenuViewModel.swift
Class MenuViewModel: ObservableObject {
@Published var toppingsList: [Topping]
init() {
toppingsList = MenuDataService.toppingsList
self.toppingsList = toppingsList
}
}
Inside the view im accessing the object using .environmentobject in the view. I'm iterating over the list of toppings using a ForEach loop, displaying the name and amount of toppings, followed by a stepper which should increment or decrement the 'amount' variable.
@EnvironmentObject private var vm = MenuViewModel
let toppingsList: [Topping]
var body: some View {
VStack {
ForEach(toppingsList, id: \.id) { topping in
Stepper("\(topping.name): \(topping.amount)", value: topping.$amount)
}
}
}
struct ExtraToppingsView_Previews: PreviewProvider {
static var previews: some View {
ExtraToppingsView(toppingsList: MenuViewModel.init().toppingsList)
.environmentObject(MenuViewModel())
}
}
I get this error in the Stepper() Line of code: Accessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update.
When clicking the '+' in the 'Cheese' stepper, it should increment the variable, and change the title to 'Cheese: 1', but the title stays the same. I'm assuming this has something to do with '@State var amount' variable, or some binding to the '$amount' variable in the stepper. If someone can point me in the right direction, it would be much appreciated.
@Statecan't be used outside of a view, so your model struct should not have any@Stateproperties. Conversely, yourlet toppingsListwill not be mutable -- it should be annotated with@State. Then, in your for each, you'll need binding. Probably a good opportunity to go through the Apple or Hacking With Swift SwiftUI tutorials and get familiar with some of the SwiftUI basics.struct ToppingisIdentifiable, you do not have to specifically use.id. Just iterate it like:ForEach(toppingsList) { topping in.