Home > Enterprise >  Referencing instance method onChange(of:perform:) on Optional requires that Binding conform to Equat
Referencing instance method onChange(of:perform:) on Optional requires that Binding conform to Equat

Time:11-11

I have the following SwiftUI View (extracted & simplified code):

struct MyView<T : Hashable>: View {
    private let selection: Binding<T?>?

    init(selection: Binding<T?>) {
        self.selection = selection
    }

    init() {
        self.selection = nil
    }

    var body: some View {
        VStack {
            ...
        }
        .onChange(of: selection) { newValue in   <== ERROR
            ...
        }
    }
}

I get the following error: Referencing instance method 'onChange(of:perform:)' on 'Optional' requires that 'Binding<T?>' conform to 'Equatable'.

How could this be resolved?

CodePudding user response:

Switch to use the wrapper

struct MyView<T : Hashable>: View {
    @Binding var selection: T?

    init(selection: Binding<T?>) {
        self._selection = selection
    }

    init() {
        //Dead end not recommended for use outside of Previews
        //Will cause undesirable behavior by mimicking having a source of truth.
        self._selection = .constant(nil)
    }

    var body: some View {
        VStack {
            Text("")
        }
        .onChange(of: selection) { newValue in   //<== ERROR
            //Do work here
        }
    }
}

https://developer.apple.com/documentation/swiftui/binding/constant(_:)

You should also note that Binding is by definition a two-way connection.

Why have a Binding if its changes will go to a dead end? You can get similar results with...

struct MyView<T : Hashable>: View {
    let selection: T?

    var body: some View {
        VStack {
            Text("")
        }.onAppear(){
            //Do work here
        }
    }
}

private let selection: Binding<T?>? is "equivalent" (but not really) to using the wrapper and then accessing $selection.

I have never dug into the reason why SwiftUI requires the wrappers vs just the types but it has to do with the DynamicProperty conformance, wrappedValue and projectedValue. The View will not know when to update if you use Binding<Type> vs @Binding.

The undesired behavior having views that will provide the user with a UX that hints that their actions are affecting something meaningful, plus there are other bugs just as jerky behavior and unresponsive UI.

  • Related