How to deal with optional selections in SwiftUI?

Viewed 33

I have a list View that takes a Binding to a selection.

struct SomeList: View {
    @Binding var selection: SomeType?

    var body: some View {
        Button("Selected") {
            selection = SomeType()
        }
    }
}

On the other side I like to know when a selection is made so I can do something with the result.

struct MainView: View {
    @State private var showSomeList: Bool = false
    @State private var someListSelection: SomeType?

    var body: some View {
        Button("Show Sheet") {
            showSomeList = true
        }
        .sheet(isPresented: $showSomeList) {
            SomeList(selection: $someListSelection)
        }
        .onChange(of: someListSelection) { //ERROR! NO OPTIONAL ALLOWED
            //Do something with the some list selection.
        }
    }
}

How can I react on the selection?

2 Answers

Here's the onChange modifier:

func onChange<V>(of value: V, perform action: @escaping (_ newValue: V) -> Void) -> some View where V : Equatable

Its completion handler expects an argument, so you must use the correct implementation:

.onChange(of: someListSelection) { newValue in

In addition, for onChange to identify when your property changes it needs the type to have some unique way of saying what is equal to what.

Hence SomeType must conform to Equatable as you can see in the top function.

There is a sheet API which is triggered by an item rather than by a Bool

struct SomeType : Identifiable { let id = UUID() }

struct MainView: View {
    @State private var someListSelection: SomeType?

    var body: some View {
        Button("Show Sheet") {
            someListSelection = SomeType()
        }
        .sheet(item: $someListSelection) { item in
            SomeList(type: item)
        }
    }
}

struct SomeList: View {
    let type: SomeType

    var body: some View {
        Text("Foo")
    }
}
Related