I have a picker that will change an attribute of an object that is bound to the view. When the picker is changed I want to update the bound object so the change is apparent in the previous view. The picker updates the label on each change but the .onChanged modifier does't fire after the first change. If changed 2 or more times the .onChanged body fires.
let categories: [String] = ["None", "Produce", "Dairy/Eggs", "Meat", "Breads", "Canned Goods", "Baking", "Frozen", "Bulk", "Snack Foods", "Spices/Seasonings", "Pasta/Rice", "Drinks", "Liquor", "Condiments"]
//Name of recipe received from previous view
@Binding var ingredient: Ingredient
//ingredient variable that can be updated
@State var category: String = ""
var body: some View {
VStack(alignment: .leading) {
Text(ingredient.name)
.font(.title)
.padding(.leading, 5)
Menu {
Picker("picker", selection: $category) {
ForEach(categories, id: \.self) {
Text($0)
}
}
.onChange(of: category, perform: { newValue in
print("PICKER CHANGED")
ingredient.category = self.category
})
.labelsHidden()
.pickerStyle(InlinePickerStyle())
} label: {
Text(category)
.foregroundColor(.black)
.padding(5)
.labelsHidden()
.clipped()
.mask(RoundedRectangle(cornerRadius: 20, style: .continuous))
}
}
.onAppear(perform: {self.category = ingredient.category})
}
Ingredient class:
class Ingredient: Identifiable, Hashable{
static func == (lhs: Ingredient, rhs: Ingredient) -> Bool {
if (lhs.id == rhs.id) {return true}
else {return false}
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
public var id = UUID()
public var name: String = ""
public var inStock: Bool = false
public var category: String = ""
public var keepInStock: Bool = false
}
CodePudding user response:
This issue is because SwiftUI does not know about the changes
Ingredient
is a class
change it to a struct
OR
make it an ObservableObject
wrap the variables in @Published
and change @Binding var ingredient: Ingredient
to @ObservedObject var ingredient: Ingredient
class
is reference type and struct
is value type.
@State
, @Binding
, @Published
see changes for value type.
@ObservedObject
, @StateObject
, and @EnvironmentObject
are for reference.
CodePudding user response:
Have you tried setting a tag
modifier on the Text
property inside the ForEach
for the picker?
Picker("picker", selection: $category) {
ForEach(categories, id: \.self) {
Text($0).tag($0)
}
}