StevenLambion/SwiftDux

Questionable Binding conformance to Equatable

Closed this issue · 2 comments

This is more of a question than an issue, but is it valid to auto-synthesize View equitability (so EquatableView can be used for efficient updates) by extending Binding as Equatable based on its wrappedValue?

extension Binding: Equatable where Value: Equatable {

Since Binding has reference semantics, the wrappedValue will always be the current value, rather than the value that was used to derive the view body at any given point in time. Do you have evidence that this is working as you expect?

What I'm really wondering is that if it is indeed a valid extension, then why isn't it done in the SwiftUI framework itself?

That is a very good question, and something I've been looking at. It was initially added to provide auto-synthesis of equatable in the returned props value of a connectable's mapping method. There were two assumptions made based on how I use the library:

  1. The state is value based (using structs).
  2. SwiftUI views will set a value on the binding multiple times, however, they only ask for a binding's value once when they're initialized. They read from the binding only when an external event trigger a view update in their containing body.

This can breakdown if the wrappedValue is derived off of a reference type. This would lead to the behavior in the second assumption, and require a manual trigger as a workaround. This trigger could be implementing updateWhen(action:). I would honestly say this is a bug that should be fixed in the library by removing the auto-closure of the StateBinder.bind(_:dispatch:) method.

The real problem I think you're getting at, however, is that it pollutes the Binding type with side-effects that are unintended. I haven't noticed any issues in my own application, but I have been thinking about other solutions to this problem. I just haven't had time to experiment with them yet.

I did a quick experiment in an Xcode Playground between the behavior of SwiftDux and pure SwiftUI when using reference types in a binding, and they're almost identically.

The one case that SwiftDux doesn't cover, which I mention in the last comment as a probable bug, is a view model using @published. To replicate the behavior in SwiftDux, StateBinder could trigger a re-render after the binding dispatches an action or I can simply remove the auto-closure from the bind method.