NEW: Learn to build amazing SwiftUI apps for macOS with my new book! >>

SOLVED: Using fetched results in a Picker.

Forums > SwiftUI

I am trying to make a picker using values from a FetchRequest. Like so:

@State var customer: Customer?

Section(header: Text("Client")) {
                Picker("Choose a client", selection: $customer) {
                    ForEach(self.customers, id: \.id) { (customer: Customer) in
                        Text("\(customer.given_name!) \(customer.family_name!)").tag(customer.id)
                    }
                }.pickerStyle(.inline)

It shows all the options in the picker but does not let me select one. Any ideas? I've read multiple articles with similar issues, but none seemed to fix my issue.

1      

Whatever you use for the .tag() has to be of the same type as whatever you use for the selection parameter. So here, you're using a Customer? as the selection but the tag is a Customer.id.

1      

So now I have

@State var customer: Customer?

and

Picker("Choose a client", selection: $customer) {
                    ForEach(self.customers, id: \.id) { (customer: Customer) in
                        Text("\(customer.given_name!) \(customer.family_name!)").tag(customer)
                    }
                }

And it's still not acknowledging the selection.

1      

Because the selection is Customer? but the tag is Customer. Those are two different types.

Perhaps the easiest way to solve this is like below. ForEach will automatically assign a tag of whatever type is used for its id parameter, which in my example I have made a UUID.

First, make sure our Customer type is Identifiable, which it already is since you have an id property; you just need to let the compiler know.

struct Customer: Identifiable {
    let id = UUID()
    //...blah blah blah
}

Then, in your View:

struct CustomerPickerView: View {

    //sample data
    let customers: [Customer] = [
        Customer(given_name: "Charlotte", family_name: "Grote"),
        Customer(given_name: "Shauna", family_name: "Wickle"),
        Customer(given_name: "Mildred", family_name: "Haversham"),
    ]

    //make the selection property the same type as your Customer.id property
    @State private var customerID = UUID()
    //we set it to a dummy value initially; 
    //the chances of an accidental collision are miniscule

    //if you want it to be set to, say, the first value in customers, do this instead:
    //@State private var customerID: UUID
    //
    //init() {
    //    _customerID = State(initialValue: customers[0].id)
    //}

    var body: some View {
        Picker("Choose a client", selection: $customerID) {
            //you don't need self.customers unless you are supporting older code (<iOS14, IIRC)
            //and you don't need to give ForEach an explicit id -
            //  since Customer has an id property, it will automatically use that
            //and you also don't need to explicitly type the parameter to the closure
            ForEach(customers) { customer in 
                Text("\(customer.given_name!) \(customer.family_name!)")
                //ForEach will automatically assign a tag of the same type as Customer.id
                //  which is the same type as customerID which we use for the selection
            }
            .onChange(of: customerID) { print($0) } //so we can watch what's going on
        }
    }
}

It's possible to use a Customer value directly as the selection; you just have to explicitly assign a tag of the correct type.

1      

What you're saying makes sense. Unfortunately, it's still not working.

1      

Could it be because the AddServiceOrderView is a presented sheet? (The file this code is in.)

1      

That shouldn't make a difference. Can you post your entire View?

1      

Checkout my answer on Stackoverflow, it touches exactly the topic with pickers and optional selection values: SwiftUI Picker with selection as struct

In short: if you have a selection variable of type Customer? you should make the tag be Customer? too.

Just use type-casting

Text("\(customer.given_name!) \(customer.family_name!)").tag(customer as Customer?)

Does this solve it?

1      

That did it! Thank you very much!

1      

Hacking with Swift is sponsored by RevenueCat

SPONSORED Spend less time managing in-app purchase infrastructure so you can focus on building your app. RevenueCat gives everything you need to easily implement, manage, and analyze in-app purchases and subscriptions without managing servers or writing backend code.

Get Started

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.