Skip to content

Commit 52c4a01

Browse files
authored
Rename BindableState to BindingState (#1855)
The -`able` naming evokes protocols in Swift, and is an outlier when considered alongside the rest of TCA's binding tools: - `BindingAction`: concrete type - `BindableAction`: protocol - `BindingReducer`: concrete type So, let's make things consistent. The one caveat is that Swift diagnostics for such a deprecation aren't great, so users won't get proactive warnings here for the time being: swiftlang/swift#63139 We may just want to keep the deprecation around till it does...
1 parent e473427 commit 52c4a01

File tree

9 files changed

+60
-52
lines changed

9 files changed

+60
-52
lines changed

Examples/CaseStudies/SwiftUICaseStudies/01-GettingStarted-Bindings-Forms.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ private let readMe = """
88
Bindable state and actions allow you to safely eliminate the boilerplate caused by needing to \
99
have a unique action for every UI control. Instead, all UI bindings can be consolidated into a \
1010
single `binding` action that holds onto a `BindingAction` value, and all bindable state can be \
11-
safeguarded with the `BindableState` property wrapper.
11+
safeguarded with the `BindingState` property wrapper.
1212
1313
It is instructive to compare this case study to the "Binding Basics" case study.
1414
"""
@@ -17,10 +17,10 @@ private let readMe = """
1717

1818
struct BindingForm: ReducerProtocol {
1919
struct State: Equatable {
20-
@BindableState var sliderValue = 5.0
21-
@BindableState var stepCount = 10
22-
@BindableState var text = ""
23-
@BindableState var toggleIsOn = false
20+
@BindingState var sliderValue = 5.0
21+
@BindingState var stepCount = 10
22+
@BindingState var text = ""
23+
@BindingState var toggleIsOn = false
2424
}
2525

2626
enum Action: BindableAction, Equatable {

Examples/CaseStudies/SwiftUICaseStudies/01-GettingStarted-FocusState.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ private let readMe = """
1010

1111
struct FocusDemo: ReducerProtocol {
1212
struct State: Equatable {
13-
@BindableState var focusedField: Field?
14-
@BindableState var password: String = ""
15-
@BindableState var username: String = ""
13+
@BindingState var focusedField: Field?
14+
@BindingState var password: String = ""
15+
@BindingState var username: String = ""
1616

1717
enum Field: String, Hashable {
1818
case username, password

Sources/ComposableArchitecture/Documentation.docc/Articles/Bindings.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,20 +177,20 @@ struct Settings: ReducerProtocol {
177177
```
178178

179179
This is a _lot_ of boilerplate for something that should be simple. Luckily, we can dramatically
180-
eliminate this boilerplate using ``BindableState``, ``BindableAction``, and ``BindingReducer``.
180+
eliminate this boilerplate using ``BindingState``, ``BindableAction``, and ``BindingReducer``.
181181

182-
First, we can annotate each bindable value of state with the ``BindableState`` property wrapper:
182+
First, we can annotate each bindable value of state with the ``BindingState`` property wrapper:
183183

184184
```swift
185185
struct Settings: ReducerProtocol {
186186
struct State: Equatable {
187-
@BindableState var digest = Digest.daily
188-
@BindableState var displayName = ""
189-
@BindableState var enableNotifications = false
187+
@BindingState var digest = Digest.daily
188+
@BindingState var displayName = ""
189+
@BindingState var enableNotifications = false
190190
var isLoading = false
191-
@BindableState var protectMyPosts = false
192-
@BindableState var sendEmailNotifications = false
193-
@BindableState var sendMobileNotifications = false
191+
@BindingState var protectMyPosts = false
192+
@BindingState var sendEmailNotifications = false
193+
@BindingState var sendMobileNotifications = false
194194
}
195195

196196
// ...

Sources/ComposableArchitecture/Documentation.docc/Extensions/SwiftUI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ The Composable Architecture can be used to power applications built in many fram
1919

2020
- <doc:Bindings>
2121
- ``ViewStore/binding(get:send:)-65xes``
22-
- ``BindableState``
22+
- ``BindingState``
2323
- ``BindableAction``
2424
- ``BindingAction``
2525
- ``BindingReducer``

Sources/ComposableArchitecture/Internal/Deprecations.swift

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import Combine
33
import SwiftUI
44
import XCTestDynamicOverlay
55

6+
// MARK: - Deprecated after 0.49.2
7+
8+
// NB: As of Swift 5.7, property wrapper deprecations are not diagnosed, so we may want to keep this
9+
// deprecation around for now:
10+
// https://github.com/apple/swift/issues/63139
11+
@available(*, deprecated, renamed: "BindingState")
12+
public typealias BindableState = BindingState
13+
614
// MARK: - Deprecated after 0.47.2
715

816
extension ActorIsolated {
@@ -972,7 +980,7 @@ extension ViewStore where ViewAction: BindableAction, ViewAction.State == ViewSt
972980
)
973981
@MainActor
974982
public subscript<Value: Equatable>(
975-
dynamicMember keyPath: WritableKeyPath<ViewState, BindableState<Value>>
983+
dynamicMember keyPath: WritableKeyPath<ViewState, BindingState<Value>>
976984
) -> Binding<Value> {
977985
self.binding(
978986
get: { $0[keyPath: keyPath].wrappedValue },
@@ -988,8 +996,8 @@ extension BindingAction {
988996
*, deprecated,
989997
message:
990998
"""
991-
For improved safety, bindable properties must now be wrapped explicitly in 'BindableState', \
992-
and accessed via key paths to that 'BindableState', like '\\.$value'
999+
For improved safety, bindable properties must now be wrapped explicitly in 'BindingState', \
1000+
and accessed via key paths to that 'BindingState', like '\\.$value'
9931001
"""
9941002
)
9951003
public static func set<Value: Equatable>(
@@ -1008,8 +1016,8 @@ extension BindingAction {
10081016
*, deprecated,
10091017
message:
10101018
"""
1011-
For improved safety, bindable properties must now be wrapped explicitly in 'BindableState', \
1012-
and accessed via key paths to that 'BindableState', like '\\.$value'
1019+
For improved safety, bindable properties must now be wrapped explicitly in 'BindingState', \
1020+
and accessed via key paths to that 'BindingState', like '\\.$value'
10131021
"""
10141022
)
10151023
public static func ~= <Value>(
@@ -1042,8 +1050,8 @@ extension ViewStore {
10421050
*, deprecated,
10431051
message:
10441052
"""
1045-
For improved safety, bindable properties must now be wrapped explicitly in 'BindableState'. \
1046-
Bindings are now derived via 'ViewStore.binding' with a key path to that 'BindableState' \
1053+
For improved safety, bindable properties must now be wrapped explicitly in 'BindingState'. \
1054+
Bindings are now derived via 'ViewStore.binding' with a key path to that 'BindingState' \
10471055
(for example, 'viewStore.binding(\\.$value)'). For dynamic member lookup to be available, \
10481056
the view store's 'Action' type must also conform to 'BindableAction'.
10491057
"""

Sources/ComposableArchitecture/SwiftUI/Binding.swift

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import SwiftUI
1111
/// Read <doc:Bindings> for more information.
1212
@dynamicMemberLookup
1313
@propertyWrapper
14-
public struct BindableState<Value> {
14+
public struct BindingState<Value> {
1515
/// The underlying value wrapped by the bindable state.
1616
public var wrappedValue: Value
1717

@@ -23,13 +23,13 @@ public struct BindableState<Value> {
2323
/// A projection that can be used to derive bindings from a view store.
2424
///
2525
/// Use the projected value to derive bindings from a view store with properties annotated with
26-
/// `@BindableState`. To get the `projectedValue`, prefix the property with `$`:
26+
/// `@BindingState`. To get the `projectedValue`, prefix the property with `$`:
2727
///
2828
/// ```swift
2929
/// TextField("Display name", text: viewStore.binding(\.$displayName))
3030
/// ```
3131
///
32-
/// See ``BindableState`` for more details.
32+
/// See ``BindingState`` for more details.
3333
public var projectedValue: Self {
3434
get { self }
3535
set { self = newValue }
@@ -41,17 +41,17 @@ public struct BindableState<Value> {
4141
/// - Returns: A new bindable state.
4242
public subscript<Subject>(
4343
dynamicMember keyPath: WritableKeyPath<Value, Subject>
44-
) -> BindableState<Subject> {
44+
) -> BindingState<Subject> {
4545
get { .init(wrappedValue: self.wrappedValue[keyPath: keyPath]) }
4646
set { self.wrappedValue[keyPath: keyPath] = newValue.wrappedValue }
4747
}
4848
}
4949

50-
extension BindableState: Equatable where Value: Equatable {}
50+
extension BindingState: Equatable where Value: Equatable {}
5151

52-
extension BindableState: Hashable where Value: Hashable {}
52+
extension BindingState: Hashable where Value: Hashable {}
5353

54-
extension BindableState: Decodable where Value: Decodable {
54+
extension BindingState: Decodable where Value: Decodable {
5555
public init(from decoder: Decoder) throws {
5656
do {
5757
let container = try decoder.singleValueContainer()
@@ -62,7 +62,7 @@ extension BindableState: Decodable where Value: Decodable {
6262
}
6363
}
6464

65-
extension BindableState: Encodable where Value: Encodable {
65+
extension BindingState: Encodable where Value: Encodable {
6666
public func encode(to encoder: Encoder) throws {
6767
do {
6868
var container = encoder.singleValueContainer()
@@ -73,29 +73,29 @@ extension BindableState: Encodable where Value: Encodable {
7373
}
7474
}
7575

76-
extension BindableState: CustomReflectable {
76+
extension BindingState: CustomReflectable {
7777
public var customMirror: Mirror {
7878
Mirror(reflecting: self.wrappedValue)
7979
}
8080
}
8181

82-
extension BindableState: CustomDumpRepresentable {
82+
extension BindingState: CustomDumpRepresentable {
8383
public var customDumpValue: Any {
8484
self.wrappedValue
8585
}
8686
}
8787

88-
extension BindableState: CustomDebugStringConvertible where Value: CustomDebugStringConvertible {
88+
extension BindingState: CustomDebugStringConvertible where Value: CustomDebugStringConvertible {
8989
public var debugDescription: String {
9090
self.wrappedValue.debugDescription
9191
}
9292
}
9393

94-
extension BindableState: Sendable where Value: Sendable {}
94+
extension BindingState: Sendable where Value: Sendable {}
9595

9696
/// An action type that exposes a `binding` case that holds a ``BindingAction``.
9797
///
98-
/// Used in conjunction with ``BindableState`` to safely eliminate the boilerplate typically
98+
/// Used in conjunction with ``BindingState`` to safely eliminate the boilerplate typically
9999
/// associated with mutating multiple fields in state.
100100
///
101101
/// Read <doc:Bindings> for more information.
@@ -116,7 +116,7 @@ extension BindableAction {
116116
///
117117
/// - Returns: A binding action.
118118
public static func set<Value: Equatable>(
119-
_ keyPath: WritableKeyPath<State, BindableState<Value>>,
119+
_ keyPath: WritableKeyPath<State, BindingState<Value>>,
120120
_ value: Value
121121
) -> Self {
122122
self.binding(.set(keyPath, value))
@@ -129,7 +129,7 @@ extension ViewStore where ViewAction: BindableAction, ViewAction.State == ViewSt
129129
/// - Parameter keyPath: A key path to a specific bindable state.
130130
/// - Returns: A new binding.
131131
public func binding<Value: Equatable>(
132-
_ keyPath: WritableKeyPath<ViewState, BindableState<Value>>,
132+
_ keyPath: WritableKeyPath<ViewState, BindingState<Value>>,
133133
file: StaticString = #file,
134134
fileID: StaticString = #fileID,
135135
line: UInt = #line
@@ -157,7 +157,7 @@ extension ViewStore where ViewAction: BindableAction, ViewAction.State == ViewSt
157157

158158
/// An action that describes simple mutations to some root state at a writable key path.
159159
///
160-
/// Used in conjunction with ``BindableState`` and ``BindableAction`` to safely eliminate the
160+
/// Used in conjunction with ``BindingState`` and ``BindableAction`` to safely eliminate the
161161
/// boilerplate typically associated with mutating multiple fields in state.
162162
///
163163
/// Read <doc:Bindings> for more information.
@@ -180,12 +180,12 @@ extension BindingAction {
180180
///
181181
/// - Parameters:
182182
/// - keyPath: A key path to the property that should be mutated. This property must be
183-
/// annotated with the ``BindableState`` property wrapper.
183+
/// annotated with the ``BindingState`` property wrapper.
184184
/// - value: A value to assign at the given key path.
185185
/// - Returns: An action that describes simple mutations to some root state at a writable key
186186
/// path.
187187
public static func set<Value: Equatable>(
188-
_ keyPath: WritableKeyPath<Root, BindableState<Value>>,
188+
_ keyPath: WritableKeyPath<Root, BindingState<Value>>,
189189
_ value: Value
190190
) -> Self {
191191
return .init(
@@ -208,14 +208,14 @@ extension BindingAction {
208208
/// // Return an authorization request effect
209209
/// ```
210210
public static func ~= <Value>(
211-
keyPath: WritableKeyPath<Root, BindableState<Value>>,
211+
keyPath: WritableKeyPath<Root, BindingState<Value>>,
212212
bindingAction: Self
213213
) -> Bool {
214214
keyPath == bindingAction.keyPath
215215
}
216216

217217
init<Value: Equatable>(
218-
keyPath: WritableKeyPath<Root, BindableState<Value>>,
218+
keyPath: WritableKeyPath<Root, BindingState<Value>>,
219219
set: @escaping (inout Root) -> Void,
220220
value: Value
221221
) {
@@ -233,15 +233,15 @@ extension BindingAction {
233233
/// key path.
234234
///
235235
/// Useful in transforming binding actions on view state into binding actions on reducer state
236-
/// when the domain contains ``BindableState`` and ``BindableAction``.
236+
/// when the domain contains ``BindingState`` and ``BindableAction``.
237237
///
238238
/// For example, we can model an feature that can bind an integer count to a stepper and make a
239239
/// network request to fetch a fact about that integer with the following domain:
240240
///
241241
/// ```swift
242242
/// struct MyFeature: ReducerProtocol {
243243
/// struct State: Equatable {
244-
/// @BindableState var count = 0
244+
/// @BindingState var count = 0
245245
/// var fact: String?
246246
/// ...
247247
/// }
@@ -279,7 +279,7 @@ extension BindingAction {
279279
/// ```swift
280280
/// extension MyFeatureView {
281281
/// struct ViewState: Equatable {
282-
/// @BindableState var count: Int
282+
/// @BindingState var count: Int
283283
/// let fact: String?
284284
/// // no access to any other state on `MyFeature.State`, like child domains
285285
/// }

Tests/ComposableArchitectureTests/BindingTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import XCTest
44
@MainActor
55
final class BindingTests: XCTestCase {
66
#if swift(>=5.7)
7-
func testNestedBindableState() {
7+
func testNestedBindingState() {
88
struct BindingTest: ReducerProtocol {
99
struct State: Equatable {
10-
@BindableState var nested = Nested()
10+
@BindingState var nested = Nested()
1111

1212
struct Nested: Equatable {
1313
var field = ""

Tests/ComposableArchitectureTests/DebugTests.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
func testBindingAction() {
4747
struct State {
48-
@BindableState var width = 0
48+
@BindingState var width = 0
4949
}
5050
let action = BindingAction.set(\State.$width, 50)
5151
var dump = ""
@@ -54,7 +54,7 @@
5454
dump,
5555
#"""
5656
BindingAction.set(
57-
WritableKeyPath<State, BindableState<Int>>,
57+
WritableKeyPath<State, BindingState<Int>>,
5858
50
5959
)
6060
"""#

Tests/ComposableArchitectureTests/RuntimeWarningTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@
190190
@MainActor
191191
func testBindingUnhandledAction() {
192192
struct State: Equatable {
193-
@BindableState var value = 0
193+
@BindingState var value = 0
194194
}
195195
enum Action: BindableAction, Equatable {
196196
case binding(BindingAction<State>)

0 commit comments

Comments
 (0)