Skip to content

Commit 65e4399

Browse files
committed
Merge remote-tracking branch 'origin/main' into ia
1 parent ed741ca commit 65e4399

File tree

26 files changed

+2241
-2002
lines changed

26 files changed

+2241
-2002
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,10 @@ Give a clear and concise description of what you expected to happen.
2525
If applicable, add screenshots to help explain your problem.
2626

2727
**Environment**
28-
- Xcode [e.g. 11.4.1]
29-
- Swift [e.g. 5.2.2]
30-
- OS (if applicable): [e.g. iOS 13]
28+
- swift-composable-architecture version [e.g. 0.20.0]
29+
- Xcode [e.g. 12.4]
30+
- Swift [e.g. 5.4]
31+
- OS: [e.g. iOS 14]
3132

3233
**Additional context**
3334
Add any more context about the problem here.

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ jobs:
2121
run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app
2222
- name: Run tests
2323
run: make test-library
24+
- name: Run benchmark
25+
if: ${{ matrix.xcode != 11.3 }}
26+
run: make benchmark
2427

2528
examples:
2629
runs-on: macos-10.15
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1250"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "swift-composable-architecture-benchmark"
18+
BuildableName = "swift-composable-architecture-benchmark"
19+
BlueprintName = "swift-composable-architecture-benchmark"
20+
ReferencedContainer = "container:">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<Testables>
31+
</Testables>
32+
</TestAction>
33+
<LaunchAction
34+
buildConfiguration = "Release"
35+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37+
launchStyle = "0"
38+
useCustomWorkingDirectory = "NO"
39+
ignoresPersistentStateOnLaunch = "NO"
40+
debugDocumentVersioning = "YES"
41+
debugServiceExtension = "internal"
42+
allowLocationSimulation = "YES">
43+
<BuildableProductRunnable
44+
runnableDebuggingMode = "0">
45+
<BuildableReference
46+
BuildableIdentifier = "primary"
47+
BlueprintIdentifier = "swift-composable-architecture-benchmark"
48+
BuildableName = "swift-composable-architecture-benchmark"
49+
BlueprintName = "swift-composable-architecture-benchmark"
50+
ReferencedContainer = "container:">
51+
</BuildableReference>
52+
</BuildableProductRunnable>
53+
</LaunchAction>
54+
<ProfileAction
55+
buildConfiguration = "Release"
56+
shouldUseLaunchSchemeArgsEnv = "YES"
57+
savedToolIdentifier = ""
58+
useCustomWorkingDirectory = "NO"
59+
debugDocumentVersioning = "YES">
60+
<BuildableProductRunnable
61+
runnableDebuggingMode = "0">
62+
<BuildableReference
63+
BuildableIdentifier = "primary"
64+
BlueprintIdentifier = "swift-composable-architecture-benchmark"
65+
BuildableName = "swift-composable-architecture-benchmark"
66+
BlueprintName = "swift-composable-architecture-benchmark"
67+
ReferencedContainer = "container:">
68+
</BuildableReference>
69+
</BuildableProductRunnable>
70+
</ProfileAction>
71+
<AnalyzeAction
72+
buildConfiguration = "Debug">
73+
</AnalyzeAction>
74+
<ArchiveAction
75+
buildConfiguration = "Release"
76+
revealArchiveInOrganizer = "YES">
77+
</ArchiveAction>
78+
</Scheme>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1300"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "swift-composable-architecture-benchmarks"
18+
BuildableName = "swift-composable-architecture-benchmarks"
19+
BlueprintName = "swift-composable-architecture-benchmarks"
20+
ReferencedContainer = "container:">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<Testables>
31+
</Testables>
32+
</TestAction>
33+
<LaunchAction
34+
buildConfiguration = "Release"
35+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37+
launchStyle = "0"
38+
useCustomWorkingDirectory = "NO"
39+
ignoresPersistentStateOnLaunch = "NO"
40+
debugDocumentVersioning = "YES"
41+
debugServiceExtension = "internal"
42+
allowLocationSimulation = "YES">
43+
<BuildableProductRunnable
44+
runnableDebuggingMode = "0">
45+
<BuildableReference
46+
BuildableIdentifier = "primary"
47+
BlueprintIdentifier = "swift-composable-architecture-benchmarks"
48+
BuildableName = "swift-composable-architecture-benchmarks"
49+
BlueprintName = "swift-composable-architecture-benchmarks"
50+
ReferencedContainer = "container:">
51+
</BuildableReference>
52+
</BuildableProductRunnable>
53+
</LaunchAction>
54+
<ProfileAction
55+
buildConfiguration = "Release"
56+
shouldUseLaunchSchemeArgsEnv = "YES"
57+
savedToolIdentifier = ""
58+
useCustomWorkingDirectory = "NO"
59+
debugDocumentVersioning = "YES">
60+
<BuildableProductRunnable
61+
runnableDebuggingMode = "0">
62+
<BuildableReference
63+
BuildableIdentifier = "primary"
64+
BlueprintIdentifier = "swift-composable-architecture-benchmarks"
65+
BuildableName = "swift-composable-architecture-benchmarks"
66+
BlueprintName = "swift-composable-architecture-benchmarks"
67+
ReferencedContainer = "container:">
68+
</BuildableReference>
69+
</BuildableProductRunnable>
70+
</ProfileAction>
71+
<AnalyzeAction
72+
buildConfiguration = "Debug">
73+
</AnalyzeAction>
74+
<ArchiveAction
75+
buildConfiguration = "Release"
76+
revealArchiveInOrganizer = "YES">
77+
</ArchiveAction>
78+
</Scheme>

Examples/CaseStudies/SwiftUICaseStudies/02-Effects-WebSocket.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ let webSocketReducer = Reducer<WebSocketState, WebSocketAction, WebSocketEnviron
102102
state.messageToSend = ""
103103

104104
return environment.webSocket.send(WebSocketId(), .string(messageToSend))
105+
.observe(on: environment.mainQueue)
105106
.map(WebSocketAction.sendResponse)
106107

107108
case let .sendResponse(error):

Examples/CaseStudies/SwiftUICaseStudies/04-HigherOrderReducers-Recursion.swift

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,14 @@ extension Reducer {
2828
}
2929

3030
struct NestedState: Equatable, Identifiable {
31-
var children: [NestedState] = []
31+
var children: IdentifiedArrayOf<NestedState> = []
3232
let id: UUID
3333
var description: String = ""
3434
}
3535

3636
indirect enum NestedAction: Equatable {
3737
case append
38-
case exclaim
39-
case node(index: Int, action: NestedAction)
38+
case node(id: NestedState.ID, action: NestedAction)
4039
case remove(IndexSet)
4140
case rename(String)
4241
}
@@ -53,24 +52,21 @@ let nestedReducer = Reducer<
5352
state.children.append(NestedState(id: environment.uuid()))
5453
return .none
5554

56-
case .exclaim:
57-
state.description += "!"
58-
return .none
59-
60-
case let .node(index, action):
61-
return self.run(&state.children[index], action, environment)
62-
.map { .node(index: index, action: $0) }
55+
case .node:
56+
return self.forEach(
57+
state: \.children,
58+
action: /NestedAction.node(id:action:),
59+
environment: { $0 }
60+
)
61+
.run(&state, action, environment)
6362

6463
case let .remove(indexSet):
6564
state.children.remove(atOffsets: indexSet)
6665
return .none
6766

6867
case let .rename(name):
69-
struct ExclaimId: Hashable {}
70-
7168
state.description = name
72-
return Effect(value: .exclaim)
73-
.debounce(id: ExclaimId(), interval: 1, scheduler: QueueScheduler.main)
69+
return .none
7470
}
7571
}
7672

@@ -83,7 +79,7 @@ struct NestedView: View {
8379
Section(header: Text(template: readMe, .caption)) {
8480

8581
ForEachStore(
86-
self.store.scope(state: \.children, action: NestedAction.node(index:action:))
82+
self.store.scope(state: \.children, action: NestedAction.node(id:action:))
8783
) { childStore in
8884
WithViewStore(childStore) { childViewStore in
8985
HStack {

Examples/CaseStudies/SwiftUICaseStudies/04-HigherOrderReducers-ResuableOfflineDownloads/ReusableComponents-Download.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,11 @@ struct CityMapDetailView: View {
147147
}
148148

149149
struct MapAppState {
150-
var cityMaps: [CityMapState]
150+
var cityMaps: IdentifiedArrayOf<CityMapState>
151151
}
152152

153153
enum MapAppAction {
154-
case cityMaps(index: Int, action: CityMapAction)
154+
case cityMaps(id: CityMapState.ID, action: CityMapAction)
155155
}
156156

157157
struct MapAppEnvironment {
@@ -161,7 +161,7 @@ struct MapAppEnvironment {
161161

162162
let mapAppReducer: Reducer<MapAppState, MapAppAction, MapAppEnvironment> = cityMapReducer.forEach(
163163
state: \MapAppState.cityMaps,
164-
action: /MapAppAction.cityMaps(index:action:),
164+
action: /MapAppAction.cityMaps(id:action:),
165165
environment: {
166166
CityMapEnvironment(
167167
downloadClient: $0.downloadClient,
@@ -179,7 +179,7 @@ struct CitiesView: View {
179179
header: Text(readMe)
180180
) {
181181
ForEachStore(
182-
self.store.scope(state: \.cityMaps, action: MapAppAction.cityMaps(index:action:))
182+
self.store.scope(state: \.cityMaps, action: MapAppAction.cityMaps(id:action:))
183183
) { cityMapStore in
184184
CityMapRowView(store: cityMapStore)
185185
.buttonStyle(BorderlessButtonStyle())
@@ -209,7 +209,7 @@ struct DownloadList_Previews: PreviewProvider {
209209
NavigationView {
210210
CityMapDetailView(
211211
store: Store(
212-
initialState: [CityMapState].mocks.first!,
212+
initialState: IdentifiedArray.mocks.first!,
213213
reducer: .empty,
214214
environment: ()
215215
)
@@ -219,7 +219,7 @@ struct DownloadList_Previews: PreviewProvider {
219219
}
220220
}
221221

222-
extension Array where Element == CityMapState {
222+
extension IdentifiedArray where ID == CityMapState.ID, Element == CityMapState {
223223
static let mocks: Self = [
224224
.init(
225225
downloadMode: .notDownloaded,

Examples/CaseStudies/SwiftUICaseStudies/04-HigherOrderReducers-ReusableFavoriting.swift

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,12 @@ let episodeReducer = Reducer<EpisodeState, EpisodeAction, EpisodeEnvironment>.em
152152
)
153153

154154
struct EpisodesState: Equatable {
155-
var episodes: [EpisodeState] = []
155+
var episodes: IdentifiedArrayOf<EpisodeState> = []
156156
var episodeSelection: EpisodeState?
157157
}
158158

159159
enum EpisodesAction: Equatable {
160-
case episode(index: Int, action: EpisodeAction)
160+
case episode(id: EpisodeState.ID, action: EpisodeAction)
161161
case episodeSelection(EpisodeAction)
162162
}
163163

@@ -169,7 +169,7 @@ struct EpisodesEnvironment {
169169
let episodesReducer: Reducer<EpisodesState, EpisodesAction, EpisodesEnvironment> =
170170
episodeReducer.forEach(
171171
state: \EpisodesState.episodes,
172-
action: /EpisodesAction.episode(index:action:),
172+
action: /EpisodesAction.episode(id:action:),
173173
environment: { EpisodeEnvironment(favorite: $0.favorite, mainQueue: $0.mainQueue) }
174174
)
175175

@@ -180,7 +180,7 @@ struct EpisodesView: View {
180180
Form {
181181
Section(header: Text(template: readMe, .caption)) {
182182
ForEachStore(
183-
self.store.scope(state: \.episodes, action: EpisodesAction.episode(index:action:))
183+
self.store.scope(state: \.episodes, action: EpisodesAction.episode(id:action:))
184184
) { rowStore in
185185
EpisodeView(store: rowStore)
186186
.buttonStyle(BorderlessButtonStyle())
@@ -229,8 +229,8 @@ func favorite<ID>(id: ID, isFavorite: Bool) -> Effect<Bool, Error> {
229229
}
230230
}
231231

232-
extension Array where Element == EpisodeState {
233-
static let mocks = [
232+
extension IdentifiedArray where ID == EpisodeState.ID, Element == EpisodeState {
233+
static let mocks: Self = [
234234
EpisodeState(id: UUID(), isFavorite: false, title: "Functions"),
235235
EpisodeState(id: UUID(), isFavorite: false, title: "Side Effects"),
236236
EpisodeState(id: UUID(), isFavorite: false, title: "Algebraic Data Types"),

Examples/CaseStudies/SwiftUICaseStudies/FactClient.swift

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ extension FactClient {
2727
})
2828
}
2929

30-
extension FactClient {
31-
// This is the "unimplemented" fact dependency that is useful to plug into tests that you want
32-
// to prove do not need the dependency.
33-
static let unimplemented = Self(
34-
fetch: { _ in
35-
XCTFail("\(Self.self).fact is unimplemented.")
36-
return .none
37-
})
38-
}
30+
#if DEBUG
31+
extension FactClient {
32+
// This is the "failing" fact dependency that is useful to plug into tests that you want
33+
// to prove do not need the dependency.
34+
static let failing = Self(
35+
fetch: { _ in
36+
XCTFail("\(Self.self).fact is unimplemented.")
37+
return .none
38+
})
39+
}
40+
#endif

Examples/CaseStudies/SwiftUICaseStudiesTests/02-Effects-BasicsTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class EffectsBasicsTests: XCTestCase {
1010
initialState: EffectsBasicsState(),
1111
reducer: effectsBasicsReducer,
1212
environment: EffectsBasicsEnvironment(
13-
fact: .unimplemented,
13+
fact: .failing,
1414
mainQueue: ImmediateScheduler()
1515
)
1616
)

0 commit comments

Comments
 (0)