Hi,
I have the following two struct definitions:
struct IngredientWrapper: Hashable, Identifiable, Codable {
var id = UUID()
var ingredientType: DrinkIngredient
var volume: Double
}
With DrinkIngredient having the following definition:
struct DrinkIngredient: Hashable, Codable {
var name: String
var ABV: Double
}
And in a parent view, I have this state variable:
@State private var ingredient: IngredientWrapper = IngredientWrapper.sample
With sample just being a sample value for the struct. The child view has the following:
@Binding var ingredient: IngredientWrapper
With it being passed to the child view in this line in the parent view:
ChildView(ingredient: $ingredient)
Finally, the child view's body:
VStack {
Picker("Ingredient", selection: $ingredient.ingredientType.name) {
ForEach(BaseNames(), id: \.self) {name in
Text(name).tag(name)
}
}
.pickerStyle(MenuPickerStyle())
Picker("Volume", selection: $ingredient.volume) {
ForEach(IngredientSizes, id: \.self) {name in
Text(name).tag(IngredientSizesDictionary[name]!)
}
}
.pickerStyle(MenuPickerStyle())
}
Picker("ABV", selection: $ingredient.ingredientType.ABV) {
ForEach(ABVoptions, id: \.self) {val in
Text(String(format: "%.1f %%", val)).tag(val)
}
}
.pickerStyle(WheelPickerStyle())
.frame(width: 100.0, height: 100.0)
.clipped()
}
.onChange(of: ingredient) {[ingredient] newValue in
print("old " + ingredient.info())
print("new " + newValue.info())
}
The BaseNames and ABVOptions and IngredientSizes and IngredientSizesDictionary are 3 arrays and one dictionary defined elsewhere. Now here is where the strange things begin. When the Volume picker is changed, onChange(of: ingredient) is called as expected. However, this is not called for the Ingredient or ABV pickers. Furthermore, when the IngredientWrapper struct is modified to:
struct IngredientWrapper: Hashable, Identifiable, Codable {
var id = UUID()
var test = false
var ingredientType: DrinkIngredient {
didSet {
print("SET")
test.toggle()
}
}
var volume: Double
}
Some very strange things start to happen. Using the ABV or Ingredient pickers does result in SET being printed, showing that the DrinkIngredient property of the IngredientWrapper struct is indeed being changed as expected. However, onChange still does not get called. The weirdest thing is, only if the Ingredient picker is set to a certain value and then tapped and set to that same value AGAIN, then onChange is called. This also does not happen if the test.toggle() line is removed.
As far as I understand, @State can be used for value types to trigger re rendering when the value type changes. This works as expected for the volume property of the IngredientWrapper struct. But didSet is showing that the ingredientType property is definitely changing as well, yet onChange is not called for this. And then the behaviour with the bool toggle is completely confusing me. Any ideas of what is happening?