@@ -151,54 +151,43 @@ public final class ViewStore<State, Action> {
151
151
self . _send ( action)
152
152
}
153
153
154
- #if canImport(SwiftUI)
155
- /// Derives a binding from the store that prevents direct writes to state and instead sends
156
- /// actions to the store.
157
- ///
158
- /// The method is useful for dealing with SwiftUI components that work with two-way `Binding`s
159
- /// since the ``Store`` does not allow directly writing its state; it only allows reading state
160
- /// and sending actions.
161
- ///
162
- /// For example, a text field binding can be created like this:
163
- ///
164
- /// ```swift
165
- /// struct State { var name = "" }
166
- /// enum Action { case nameChanged(String) }
167
- ///
168
- /// TextField(
169
- /// "Enter name",
170
- /// text: viewStore.binding(
171
- /// get: { $0.name },
172
- /// send: { Action.nameChanged($0) }
173
- /// )
174
- /// )
175
- /// ```
176
- ///
177
- /// - Parameters:
178
- /// - get: A function to get the state for the binding from the view
179
- /// store's full state.
180
- /// - localStateToViewAction: A function that transforms the binding's value
181
- /// into an action that can be sent to the store.
182
- /// - Returns: A binding.
183
- @available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
184
- public func binding< LocalState> (
185
- get: @escaping ( State ) -> LocalState ,
186
- send localStateToViewAction: @escaping ( LocalState ) -> Action
187
- ) -> Binding < LocalState > {
188
- Binding (
189
- get: { get ( self . _state) } ,
190
- set: { newLocalState, transaction in
191
- if transaction. animation != nil {
192
- withTransaction ( transaction) {
193
- self . send ( localStateToViewAction ( newLocalState) )
194
- }
195
- } else {
196
- self . send ( localStateToViewAction ( newLocalState) )
197
- }
198
- }
199
- )
200
- }
201
-
154
+ #if canImport(SwiftUI)
155
+ /// Derives a binding from the store that prevents direct writes to state and instead sends
156
+ /// actions to the store.
157
+ ///
158
+ /// The method is useful for dealing with SwiftUI components that work with two-way `Binding`s
159
+ /// since the ``Store`` does not allow directly writing its state; it only allows reading state
160
+ /// and sending actions.
161
+ ///
162
+ /// For example, a text field binding can be created like this:
163
+ ///
164
+ /// ```swift
165
+ /// struct State { var name = "" }
166
+ /// enum Action { case nameChanged(String) }
167
+ ///
168
+ /// TextField(
169
+ /// "Enter name",
170
+ /// text: viewStore.binding(
171
+ /// get: { $0.name },
172
+ /// send: { Action.nameChanged($0) }
173
+ /// )
174
+ /// )
175
+ /// ```
176
+ ///
177
+ /// - Parameters:
178
+ /// - get: A function to get the state for the binding from the view
179
+ /// store's full state.
180
+ /// - localStateToViewAction: A function that transforms the binding's value
181
+ /// into an action that can be sent to the store.
182
+ /// - Returns: A binding.
183
+ @available ( iOS 13 . 0 , OSX 10 . 15 , tvOS 13 . 0 , watchOS 6 . 0 , * )
184
+ public func binding< LocalState> (
185
+ get: @escaping ( State ) -> LocalState ,
186
+ send localStateToViewAction: @escaping ( LocalState ) -> Action
187
+ ) -> Binding < LocalState > {
188
+ ObservedObject ( wrappedValue: self )
189
+ . projectedValue [ get: . init( rawValue: get) , send: . init( rawValue: localStateToViewAction) ]
190
+ }
202
191
/// Derives a binding from the store that prevents direct writes to state and instead sends
203
192
/// actions to the store.
204
193
///
@@ -296,6 +285,14 @@ public final class ViewStore<State, Action> {
296
285
deinit {
297
286
viewDisposable? . dispose ( )
298
287
}
288
+
289
+ private subscript< LocalState> (
290
+ get state: HashableWrapper < ( State ) -> LocalState > ,
291
+ send action: HashableWrapper < ( LocalState ) -> Action >
292
+ ) -> LocalState {
293
+ get { state. rawValue ( self . state) }
294
+ set { self . send ( action. rawValue ( newValue) ) }
295
+ }
299
296
}
300
297
301
298
extension ViewStore where State: Equatable {
@@ -353,3 +350,9 @@ public struct StoreProducer<State>: SignalProducerConvertible {
353
350
self . upstream. map ( keyPath) . skipRepeats ( )
354
351
}
355
352
}
353
+
354
+ private struct HashableWrapper < Value> : Hashable {
355
+ let rawValue : Value
356
+ static func == ( lhs: Self , rhs: Self ) -> Bool { false }
357
+ func hash( into hasher: inout Hasher ) { }
358
+ }
0 commit comments