Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EquatableView not forcing SwiftUI to use custom implementation of the == function

I am unable to use the EquatableView as per the article: Link1 and link2. I expected the "==" function in the TestView to be invoked every time I click on the Button.

Am I missing something here?

struct ContentView: View {   
    @State var state = false   
    var body: some View {
        VStack {
            EquatableView(content: TestView(state: $state))
            Button("Change state", action: {state.toggle()})
        }
    }
}

struct TestView: View, Equatable {
    @Binding var state: Bool
    var body: some View {
        let _ = print("Test updated")
        Text("TestView state : \(state.description)")
    }
    static func == (lhs: TestView, rhs: TestView) -> Bool {
        //Never printed or invoked
        let _ = print ("lhs == rhs invoked  \(lhs.state) == \(rhs.state)") 
        return lhs.state == rhs.state
    }
}

UPDATE:

After very helpful response from Alperen, it shows that “@State” has to be added for == to be triggered. However, passing a "@State" var from parent directly to SubView's "@State" for the same var, as suggested below, makes no sense.

So, I added another variable to TestView “@State var notUsed“ which will not work unless "@Binding" is removed. One would also want to compare "@Binding" vars, so to me this is illogical.

My question still remains, am I missing something or is this behaviour by design?

like image 993
tatamata Avatar asked Oct 16 '25 02:10

tatamata


1 Answers

Equatable is used when a view is created, so either it should replace already existed or not. In your example TestView is not re-created, because it should not on binding changed - only body rendered with new value.

To simulate recreation (for testing purpose) the simplest it to add condition. Equatibility is just a optimisation technic it helps SwiftUI to detect replace existed view instance or not.

Here is updated example to demo Equatable works. Tested with Xcode 12.1 / iOS 14.1

struct ContentView: View {
    @State var state = false
    var body: some View {
        VStack {
            if state {
               EquatableView(content: TestView(state: $state))
            }
            Button("Change state", action: {state.toggle()})
        }
    }
}

struct TestView: View, Equatable {
    @Binding var state: Bool
    init(state: Binding<Bool>) {
        _state = state
        print(">> inited")        // << check if created
    }
    var body: some View {
        let _ = print("Test updated")
        Text("TestView state : \(state.description)")
    }
    static func == (lhs: TestView, rhs: TestView) -> Bool {
        //Never printed or invoked
        let _ = print ("lhs == rhs invoked  \(lhs.state) == \(rhs.state)")
        return lhs.state == rhs.state
    }
}
like image 60
Asperi Avatar answered Oct 17 '25 17:10

Asperi



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!