[FIXED] SwiftUI Picker in wiederverwendbarer Komponente mit Protokoll kann Hashable nicht entsprechen

Ausgabe

Ich versuche, eine wiederverwendbare Komponente zu erstellen, die einen SwiftUI-Picker enthält, der an mehreren Stellen in meiner App mit verschiedenen Typen arbeiten kann. Ich habe ein Pickable-Protokoll erstellt, das Hashable entspricht, aber wenn ich versuche, es zu verwenden, beschweren sich Picker und ForEach, dass Type ‘any Pickable’ nicht ‘Hashable’ entsprechen kann.

import SwiftUI

struct PickerRow: View {
    let title: String
    let options: [any Pickable]
    @State var selection: any Pickable
    
    var body: some View {
        HStack {
            Spacer()
            Text(title)
                .font(.subHeading)
            Picker(title, selection: $selection, content: {
                ForEach(options, id: \.self) {
                    Text($0.name)
                }
            }).pickerStyle(.menu)
        }
    }
}

protocol Pickable: Hashable {
    var name: String { get }
}

Gibt es eine Möglichkeit, so etwas zum Laufen zu bringen, ohne einen konkreten Typ anzugeben?

Lösung

Wenn man darüber nachdenkt, macht es Sinn.

Was würden Sie erwarten, wenn dieser Code gültig wäre und Sie ihn so verwenden würden?

struct ContentView: View {
    let options = [PickableA(), PickableB()]
    @State var selection = PickableC()
    var body: some View {
        PickerRow(title: "Choose one", options: options, selection: $selection)
    }
}

Das kann unmöglich funktionieren, oder?

Was Sie brauchen, ist eine Möglichkeit, um sicherzustellen, dass es eine Einschränkung gibt, die zwingt , optionsund selectionvom gleichen konkreten Typ zu sein (denken Sie Equatablebeispielsweise daran, dass sowohl Stringals Intauch konform sind, aber Sie können sie nicht vergleichen).

Eine mögliche Lösung wäre eine generische Einschränkung in der Deklaration Ihrer Struktur (beachten Sie auch das @Bindingstatt, @Stateda wir externe Werte ändern):

struct PickerRow<Option: Pickable>: View {
    let title: String
    let options: [Option]
    @Binding var selection: Option
    
    var body: some View {
        HStack {
            Spacer()
            Text(title)
                .font(.subheadline)
            Picker(title, selection: $selection) {
                ForEach(options, id: \.self) {
                    Text($0.name)
                }
            }.pickerStyle(.menu)
        }
    }
}

die du so verwenden könntest:

struct Person: Pickable {
    let name: String
}

struct ContentView: View {
    let options = [Person(name: "Bob"), Person(name: "Alice")]
    @State var selection = Person(name: "Bob")
    var body: some View {
        PickerRow(title: "Choose one", options: options, selection: $selection)
    }
}


Beantwortet von –
Alladinian


Antwort geprüft von –
Clifford M. (FixError Volunteer)

0 Shares:
Leave a Reply

Your email address will not be published. Required fields are marked *

You May Also Like