Search code examples
iosswiftswiftuiprotocols

Cannot convert value of type 'Binding<T: P>' to expected argument type 'Binding<any P>'


I have the following:

protocol SomeSelectorRow : CustomStringConvertible, CaseIterable, Identifiable {
}

struct SomeSelector : View {
    @Binding var selectedRow: any SomeSelectorRow
    var rows: [any SomeSelectorRow]

    var body: some View {
        List {
            ForEach(rows) { row in
                Button {
                    selectedRow = row
                } label: {
                    HStack {
                        Label(title: { Text(row.description) },
                              icon: { row == selectedRow ? imageA
                                                         : imageB })
                    }
                }
            }
        }
    }
}

Which I use like this:

enum SomeEnum : String, SomeSelectorRow {
    case one = "one"
    case two = "two"
    case three = "three"

    var id: SomeEnum { self }

    var description: String {
        return self.rawValue
    }
}

...

struct MyView : View {
    @Binding var selection: SomeEnum

    var body: some View {
        SomeSelector(selectedRow: $selection, rows: SomeEnum.allCases) <= ERROR
    }
}

On the indicated line I get the following error on $selection:

Cannot convert value of type Binding<SomeEnum> to expected argument type Binding<any SomeSelectorRow>

I find this odd because SomeEnum is a SomeSelectorRow.

Why does this happen and what can I do about it?


Solution

  • SomeEnum is a concrete type. any SomeSelectorRow is not equivalent. You may want to make SomeSelector generic:

    struct SomeSelector<T: SomeSelectorRow>: View {
        @Binding var selectedRow: T
        var rows: [T]
        // …
    }
    

    Then when you use SomeEnum it will produce an instance of SomeSelector specifically typed for SomeEnum.