Issue #716

I have an enum that conforms to CaseIterable that I want to show in Picker

enum Position: String, Codable, CaseIterable, Identifiable {
    var id: String { rawValue }
    case left
    case right
    case bottom
    case top
}

Picker(selection: $preference.position, label: Text("Position")) {
    ForEach(Preference.Position.allCases) { position in
        Text(position.rawValue)
    }
}

It compiles and runs just fine, but Picker does not show current selection regardless of any Picker style I choose. It does not update Binding at all.

The fix is to specify id, it looks redundant because of enum conforms to Identifiable, but it fixes the problem

Picker(selection: $preference.position, label: Text("Position")) {
    ForEach(Preference.Position.allCases, id: \.self) { position in
        Text(position.rawValue)
    }
}

Mismatch between rawValue and enum case itself

Reading ForEach once again

init(_ data: Data, content: @escaping (Data.Element) -> Content)

Available when Data conforms to RandomAccessCollection, ID is Data.Element.ID, Content conforms to View, and Data.Element conforms to Identifiable.

So in our case, we use rawValue as id for Identifiable, so there’s mismatch between our selection being enum case and items in ForEach, which uses rawValue to uniquely identifies items. So our fix is to explicitly state that we want to use the enum case itself \.self as idfor ForEach

What we can also do is to declare enum case itself as id

enum Position: String, Codable, CaseIterable, Identifiable {
    var id: Position { self }
    case left
    case right
    case bottom
    case top
}

The lesson learned here is we need to ensure the underlying type of selection in List and id used in ForEach are the same