Why my SwiftUI Picker doesn't recognize my selection?

September 15, 20233 min read#ios, #swiftui, #swift

While working on a new feature for my SimRecorder app, I found an interesting issue with SwiftUI Picker that I want to share with you.

The problem

I want to display a SwiftUI View, containing a Picker, so that users can choose a Simulator from the list of booted Simulators to work with. The ID of the selected simulator is stored in the selectedSimulator variable which has the type Simulator

struct SimulatorSettingsSideBarView: View {
    @ObservedObject var controller: SimulatorsController

    @State private var selectedSimulator: Simulator?

    var body: some View {
        VStack(alignment: .leading) {
            List {
                Section("Simulators") {
                    Picker(
                        "",
                        selection: $selectedSimulator
                    ) {
                        ForEach(controller.bootedSimulators, id: \.self) {
                            Text($0.name)
                                .tag($0)
                        }
                    }
                    .labelsHidden()
                }
            }

            Spacer()
        }
    }
}

The problem is that, when I run the above code, the Picker will not persist my selection. As you can see in the video, the Picker reset itself to the not-selected state whenever users choose a simulator.

picker_not_working

The Solution

After reading the Picker’s Apple Documentation carefully again, I found this important sentence

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(_:).

As the selectedSimulator has the type of Simulator? to indicate a not-selected state when its value equals nil. The doc indicates that we need to do something else to make Picker work properly.

Following the link to the tag(_:) method documentation, I can see this important sentence

The Picker requires the tags to have a type that exactly matches the selection type, which in this case is an optional Flavor

From there, I can easily fix my issue by casting the parameters in the tag method to the same optional Simulator type to match the type of selectedSimulator variable

struct SimulatorSettingsSideBarView: View {
    ....
    var body: some View {
                .....
                            Text($0.name)
                                .tag($0 as Simulator?)
                .....
    }
}

Now, everything is working as expected

picker_working

Conclusion

Hopefully, this short post will save you some time when investigating why your Picker View doesn’t work. The learning here can be compressed in this important sentence from the Apple Documentation

The Picker requires the tags to have a type that exactly matches the selection type

Quick Drop logo

Profile picture

Personal blog by An Tran. I'm focusing on creating useful apps.
#Swift #Kotlin #Mobile #MachineLearning #Minimalist


© An Tran - 2024