Skip to content

Commit f615959

Browse files
authored
Add Binding.removeDuplicates() (pointfreeco#11)
* Add `Binding.removeDuplicates()` Because this library makes it easy to add logic around navigation, it's probably also a good idea to ship with helpers that work around some surprising bugs/behaviors that currently exist in SwiftUI. For example, as noticed by pointfreeco#10, `NavigationLink` writes `nil` to its binding twice on dismissal. It's probably not appropriate for us to automatically filter duplicate writes, but we can at least ship a `Binding.removeDuplicates()` that makes it easy to achieve this behavior. * wip
1 parent 7a61fb4 commit f615959

File tree

1 file changed

+34
-0
lines changed

1 file changed

+34
-0
lines changed

Sources/SwiftUINavigation/Binding.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,38 @@ extension Binding {
133133
where Value == Enum? {
134134
self.case(casePath).isPresent()
135135
}
136+
137+
/// Creates a binding that ignores writes to its wrapped value when equivalent to the new value.
138+
///
139+
/// Useful to minimize writes to bindings passed to SwiftUI APIs. For example, [`NavigationLink`
140+
/// may write `nil` twice][FB9404926] when dismissing its destination via the navigation bar's
141+
/// back button. Logic attached to this dismissal will execute twice, which may not be desirable.
142+
///
143+
/// [FB9404926]: https://gist.github.com/mbrandonw/70df235e42d505b3b1b9b7d0d006b049
144+
///
145+
/// - Parameter isDuplicate: A closure to evaluate whether two elements are equivalent, for
146+
/// purposes of filtering writes. Return `true` from this closure to indicate that the second
147+
/// element is a duplicate of the first.
148+
public func removeDuplicates(by isDuplicate: @escaping (Value, Value) -> Bool) -> Self {
149+
.init(
150+
get: { self.wrappedValue },
151+
set: { newValue, transaction in
152+
guard !isDuplicate(self.wrappedValue, newValue) else { return }
153+
self.transaction(transaction).wrappedValue = newValue
154+
}
155+
)
156+
}
157+
}
158+
159+
extension Binding where Value: Equatable {
160+
/// Creates a binding that ignores writes to its wrapped value when equivalent to the new value.
161+
///
162+
/// Useful to minimize writes to bindings passed to SwiftUI APIs. For example, [`NavigationLink`
163+
/// may write `nil` twice][FB9404926] when dismissing its destination via the navigation bar's
164+
/// back button. Logic attached to this dismissal will execute twice, which may not be desirable.
165+
///
166+
/// [FB9404926]: https://gist.github.com/mbrandonw/70df235e42d505b3b1b9b7d0d006b049
167+
public func removeDuplicates() -> Self {
168+
self.removeDuplicates(by: ==)
169+
}
136170
}

0 commit comments

Comments
 (0)