Skip to content

Commit 663a45f

Browse files
Fix WithViewStore initializer ambiguity (#2278)
* Test to show when ambiguous init of ViewStore happens * Fix #2275 * wip --------- Co-authored-by: Johan Kool <[email protected]>
1 parent d2d3c14 commit 663a45f

File tree

4 files changed

+47
-7
lines changed

4 files changed

+47
-7
lines changed

Sources/ComposableArchitecture/SwiftUI/Binding.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ extension WithViewStore where Content: View {
289289
/// - isDuplicate: A function to determine when two `ViewState` values are equal. When values
290290
/// are equal, repeat view computations are removed.
291291
/// - content: A function that can generate content from a view store.
292+
@_disfavoredOverload
292293
public init<State, Action>(
293294
_ store: Store<State, Action>,
294295
observe toViewState: @escaping (BindingViewStore<State>) -> ViewState,
@@ -328,6 +329,7 @@ extension WithViewStore where Content: View {
328329
/// - isDuplicate: A function to determine when two `ViewState` values are equal. When values
329330
/// are equal, repeat view computations are removed.
330331
/// - content: A function that can generate content from a view store.
332+
@_disfavoredOverload
331333
public init<State>(
332334
_ store: Store<State, ViewAction>,
333335
observe toViewState: @escaping (BindingViewStore<State>) -> ViewState,
@@ -360,6 +362,7 @@ extension WithViewStore where ViewState: Equatable, Content: View {
360362
/// All changes to the view state will cause the `WithViewStore` to re-compute its view.
361363
/// - fromViewAction: A function that transforms view actions into store action.
362364
/// - content: A function that can generate content from a view store.
365+
@_disfavoredOverload
363366
public init<State, Action>(
364367
_ store: Store<State, Action>,
365368
observe toViewState: @escaping (BindingViewStore<State>) -> ViewState,
@@ -389,6 +392,7 @@ extension WithViewStore where ViewState: Equatable, Content: View {
389392
/// - toViewState: A function that transforms binding store state into observable view state.
390393
/// All changes to the view state will cause the `WithViewStore` to re-compute its view.
391394
/// - content: A function that can generate content from a view store.
395+
@_disfavoredOverload
392396
public init<State>(
393397
_ store: Store<State, ViewAction>,
394398
observe toViewState: @escaping (BindingViewStore<State>) -> ViewState,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import Combine
2+
@_spi(Internals) import ComposableArchitecture
3+
import XCTest
4+
import SwiftUI
5+
6+
@MainActor
7+
final class BindableStoreTests: XCTestCase {
8+
func testBindableStore() {
9+
struct BindableReducer: ReducerProtocol {
10+
struct State: Equatable {
11+
@BindingState var something: Int
12+
}
13+
14+
enum Action: BindableAction {
15+
case binding(BindingAction<State>)
16+
}
17+
18+
var body: some ReducerProtocol<State, Action> {
19+
BindingReducer()
20+
}
21+
}
22+
23+
struct SomeView: View {
24+
let store: StoreOf<BindableReducer>
25+
26+
struct ViewState: Equatable {}
27+
28+
var body: some View {
29+
WithViewStore(store, observe: { _ in ViewState() }) { viewStore in
30+
EmptyView()
31+
}
32+
}
33+
}
34+
}
35+
}

Tests/ComposableArchitectureTests/StoreTests.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ final class StoreTests: BaseTCATestCase {
1111

1212
XCTAssertEqual(store.effectCancellables.count, 0)
1313

14-
_ = store.send(())
14+
store.send(())
1515

1616
XCTAssertEqual(store.effectCancellables.count, 0)
1717
}
@@ -36,7 +36,7 @@ final class StoreTests: BaseTCATestCase {
3636

3737
XCTAssertEqual(store.effectCancellables.count, 0)
3838

39-
_ = store.send(.start)
39+
store.send(.start)
4040

4141
XCTAssertEqual(store.effectCancellables.count, 1)
4242

@@ -795,7 +795,7 @@ final class StoreTests: BaseTCATestCase {
795795
$0.date = .constant(Date(timeIntervalSinceReferenceDate: 1_234_567_890))
796796
}
797797

798-
_ = store.send(.tap)
798+
store.send(.tap)
799799
XCTAssertEqual(store.state.value.date, Date(timeIntervalSinceReferenceDate: 1_234_567_890))
800800
}
801801

@@ -879,7 +879,7 @@ final class StoreTests: BaseTCATestCase {
879879
.sink { _ in storeStateCount2 += 1 }
880880
.store(in: &self.cancellables)
881881

882-
_ = store.send(.tap)
882+
store.send(.tap)
883883
XCTAssertEqual(removeDuplicatesCount1, 0)
884884
XCTAssertEqual(stateScopeCount1, 2)
885885
XCTAssertEqual(viewStoreCount1, 0)
@@ -888,7 +888,7 @@ final class StoreTests: BaseTCATestCase {
888888
XCTAssertEqual(stateScopeCount2, 2)
889889
XCTAssertEqual(viewStoreCount2, 0)
890890
XCTAssertEqual(storeStateCount2, 1)
891-
_ = store.send(.tap)
891+
store.send(.tap)
892892
XCTAssertEqual(removeDuplicatesCount1, 0)
893893
XCTAssertEqual(stateScopeCount1, 3)
894894
XCTAssertEqual(viewStoreCount1, 0)
@@ -898,7 +898,7 @@ final class StoreTests: BaseTCATestCase {
898898
XCTAssertEqual(viewStoreCount2, 0)
899899
XCTAssertEqual(storeStateCount2, 1)
900900

901-
_ = store.send(.child(.dismiss))
901+
store.send(.child(.dismiss))
902902
_ = (childViewStore1, childViewStore2, childStore1, childStore2)
903903
}
904904
}

Tests/ComposableArchitectureTests/TestStoreNonExhaustiveTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,8 @@
894894
XCTTODO(
895895
"""
896896
This test should pass once we have the concept of "copyable" dependencies.
897-
""")
897+
"""
898+
)
898899

899900
let store = TestStore(initialState: Feature.State()) {
900901
Feature()

0 commit comments

Comments
 (0)