Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI Picker with selection as struct

Iam trying to use Picker as selection of struct. Let say I have a struct "Pet" like below

struct Pet: Identifiable, Codable, Hashable {

    let id = UUID()
    let name: String
    let age: Int
}

I am getting all Pet's from some class, where Pets are defined as @Published var pets = Pet

static let pets = Class().pets

I would like to be able to write a selection from picker to below variable:

@State private var petSelection: Pet?

Picker is:

Picker("Pet", selection: $petSelection){
                    ForEach(Self.pets) { item in
                        Text(item.name)

                    }
                }

Picker shows properly all avaliavble pets but when I chose one petSelection has been not changed (nil). How should I mange it?

Thanks!

Edit:

Of course I know that I can use tag like below:

Picker("Pet", selection: $petSelection) {
ForEach(0 ..< Self.pet.count) { index in
    Text(Self.pet[index].name).tag(index)
    }

But wonder is it possible to use struct as selection. Thanks

like image 216
Pa Bloo Avatar asked Jul 09 '26 08:07

Pa Bloo


2 Answers

Short answer: The type associated with the tag of the entries in your Picker (the Texts) must be identical to the type used for storing the selection.

From Picker docs:

Use an optional value for the selection input parameter. For that to work, you need to explicitly cast the tag modifier’s input as Optional to match. For an example of this, see tag(_:).

In your example: You have an optional selection (probably to allow "empty selection") of Pet?, but the array passed to ForEach is of type [Pet]. You have to add therefore a .tag(item as Pet?) to your entries to ensure the selection works.

ForEach(Self.pets) { item in
    Text(item.name).tag(item as Pet?)
}

Here follows my initial, alternate answer (getting rid of the optionality):

You have defined your selection as an Optional of your struct: Pet?. It seems that the Picker cannot handle Optional structs properly as its selection type.

As soon as you get rid of the optional for example by introducing a "dummy/none-selected Pet", Picker starts working again:

extension Pet {
    static let emptySelection = Pet(name: "", age: -1)
}

in your view initialise the selection:

@State private var petSelection: Pet = .emptySelection

I hope this helps you too.

like image 170
pd95 Avatar answered Jul 11 '26 23:07

pd95


You use the following way:

 @Published var  pets: [Pet?] = [ nil, Pet(name: "123", age: 23), Pet(name: "123dd", age: 243),]

     VStack{
      Text(petSelection?.name ??  "name")
      Picker("Pet", selection: $petSelection){
         ForEach(Self.pets, id: \.self) { item in
            Text(item?.name ?? "name").tag(item)
       }}}
like image 34
E.Coms Avatar answered Jul 11 '26 22:07

E.Coms



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!