I post the minimum code to reproduce the behavior. Tested on latest macOS and Xcode.
The picker in this example is just a wrapper for the default picker and conforms to Equatable (this is a must to prevent the view from updating when properties doesn't change in the real world view) and categories:
enum Category: Int, Identifiable, CaseIterable {
case one, two, three
var id: Self { self }
var name: String {
switch self {
case .one:
return "First"
case .two:
return "Second"
case .three:
return "Third"
}
}
}
struct CustomPicker: View, Equatable {
static func == (lhs: CustomPicker, rhs: CustomPicker) -> Bool {
lhs.selectedCategory == rhs.selectedCategory
}
@Binding var selectedCategory: Category
var body: some View {
VStack {
Picker("Picker", selection: $selectedCategory) {
ForEach(Category.allCases) { category in
Text(category.name)
}
}
}
}
}
And a simple model to bind to:
final class Model: ObservableObject {
@Published var selectedCategory: Category = .two
}
Now in ContentView:
struct ContentView: View {
@StateObject private var model = Model()
@State private var selectedCategory: Category = .two
var body: some View {
VStack {
Text("Picker bug")
HStack {
CustomPicker(selectedCategory: $selectedCategory)
CustomPicker(selectedCategory: $model.selectedCategory)
}
}
.padding()
}
}
Here is the problem. If I bind the CustomPicker to the @Stateproperty it works as expected. However, if bound to the model's @Published property the value doesn't change when interacting with the control. When not using the Equatable conformance it works as expected.
What's more interesting is that if I change the pickerStyle to something else like segmented or inline it does work again.
Any idea why this happens? Probably a bug?
EDIT:
I found a hack/workaround... the thing is if the CustomPicker is inside a regular TabView it works fine.
TabView {
CustomPicker(selectedCategory: $model.selectedCategory)
.tabItem {
Text("Hack")
}
}
Strange behavior...
CustomPickerEquatable? Can you explainIf I bind the CustomPicker to the @State property it works as expected. CustomPicker is aViewit is not to be assigned to a@State property.selectedCategory. In this example I put two of them side by side binding their properties to the parent in two different ways. One being an @State property in the parent and the other being an @Published property en an ObservableObject declared @StateObject in the parent.CustomPickerEquatable, just remove theEquatableand the static func.idor something, thisEquatablemay be intersting but let the system take care of things.