Skip to content

Commit c9cb61f

Browse files
authored
Merge pull request #42 from CombineCommunity/feature/use-replay-subject
Feature/use replay subject
2 parents f2d4483 + a774dfa commit c9cb61f

34 files changed

Lines changed: 275 additions & 186 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
**v0.4.0 - Bane**:
2+
3+
- replace CurrentValueSubject by a ReplaySubject in System.stream
4+
15
**v0.3.0 - Tyranus**:
26

37
- Feedback: introduce the "on:" keyword to explicitly declare the type of state that concerns the side effect

Examples/Examples.xcodeproj/project.pbxproj

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
1A7057E7266167540070FD5D /* Feedbacks in Frameworks */ = {isa = PBXBuildFile; productRef = 1A7057E6266167540070FD5D /* Feedbacks */; };
11+
1A7057E9266167950070FD5D /* FeedbacksTest in Frameworks */ = {isa = PBXBuildFile; productRef = 1A7057E8266167950070FD5D /* FeedbacksTest */; };
1012
741C474025EC5CDB00F1231B /* Counter+TransitionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 741C473F25EC5CDB00F1231B /* Counter+TransitionsTests.swift */; };
11-
741C475C25EC5DE100F1231B /* Feedbacks in Frameworks */ = {isa = PBXBuildFile; productRef = 741C475B25EC5DE100F1231B /* Feedbacks */; };
12-
741C476625EC5E4C00F1231B /* FeedbacksTest in Frameworks */ = {isa = PBXBuildFile; productRef = 741C476525EC5E4C00F1231B /* FeedbacksTest */; };
1313
742FEE2425B388DA00575CB2 /* GifList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742FEE2325B388DA00575CB2 /* GifList.swift */; };
1414
742FEE2825B38B1A00575CB2 /* GifList+States.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742FEE2725B38B1A00575CB2 /* GifList+States.swift */; };
1515
742FEE2E25B38EEE00575CB2 /* GifOverview.swift in Sources */ = {isa = PBXBuildFile; fileRef = 742FEE2D25B38EEE00575CB2 /* GifOverview.swift */; };
@@ -66,6 +66,7 @@
6666
/* End PBXContainerItemProxy section */
6767

6868
/* Begin PBXFileReference section */
69+
1A5E6478266166CA00F576A9 /* Feedbacks */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Feedbacks; path = ..; sourceTree = "<group>"; };
6970
741C473D25EC5CDB00F1231B /* ExamplesTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExamplesTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
7071
741C473F25EC5CDB00F1231B /* Counter+TransitionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Counter+TransitionsTests.swift"; sourceTree = "<group>"; };
7172
741C474125EC5CDB00F1231B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -121,15 +122,15 @@
121122
isa = PBXFrameworksBuildPhase;
122123
buildActionMask = 2147483647;
123124
files = (
124-
741C476625EC5E4C00F1231B /* FeedbacksTest in Frameworks */,
125+
1A7057E9266167950070FD5D /* FeedbacksTest in Frameworks */,
125126
);
126127
runOnlyForDeploymentPostprocessing = 0;
127128
};
128129
7471829D25AE7B0B0098E83E /* Frameworks */ = {
129130
isa = PBXFrameworksBuildPhase;
130131
buildActionMask = 2147483647;
131132
files = (
132-
741C475C25EC5DE100F1231B /* Feedbacks in Frameworks */,
133+
1A7057E7266167540070FD5D /* Feedbacks in Frameworks */,
133134
);
134135
runOnlyForDeploymentPostprocessing = 0;
135136
};
@@ -297,6 +298,7 @@
297298
7471829725AE7B0B0098E83E = {
298299
isa = PBXGroup;
299300
children = (
301+
1A5E6478266166CA00F576A9 /* Feedbacks */,
300302
747182A225AE7B0B0098E83E /* Examples */,
301303
741C473E25EC5CDB00F1231B /* ExamplesTests */,
302304
747182A125AE7B0B0098E83E /* Products */,
@@ -400,7 +402,7 @@
400402
);
401403
name = ExamplesTests;
402404
packageProductDependencies = (
403-
741C476525EC5E4C00F1231B /* FeedbacksTest */,
405+
1A7057E8266167950070FD5D /* FeedbacksTest */,
404406
);
405407
productName = ExamplesTests;
406408
productReference = 741C473D25EC5CDB00F1231B /* ExamplesTests.xctest */;
@@ -420,7 +422,7 @@
420422
);
421423
name = Examples;
422424
packageProductDependencies = (
423-
741C475B25EC5DE100F1231B /* Feedbacks */,
425+
1A7057E6266167540070FD5D /* Feedbacks */,
424426
);
425427
productName = Examples;
426428
productReference = 747182A025AE7B0B0098E83E /* Examples.app */;
@@ -454,7 +456,6 @@
454456
);
455457
mainGroup = 7471829725AE7B0B0098E83E;
456458
packageReferences = (
457-
741C475A25EC5DE100F1231B /* XCRemoteSwiftPackageReference "Feedbacks" */,
458459
);
459460
productRefGroup = 747182A125AE7B0B0098E83E /* Products */;
460461
projectDirPath = "";
@@ -789,26 +790,13 @@
789790
};
790791
/* End XCConfigurationList section */
791792

792-
/* Begin XCRemoteSwiftPackageReference section */
793-
741C475A25EC5DE100F1231B /* XCRemoteSwiftPackageReference "Feedbacks" */ = {
794-
isa = XCRemoteSwiftPackageReference;
795-
repositoryURL = "git@github.com:CombineCommunity/Feedbacks.git";
796-
requirement = {
797-
kind = exactVersion;
798-
version = 0.3.0;
799-
};
800-
};
801-
/* End XCRemoteSwiftPackageReference section */
802-
803793
/* Begin XCSwiftPackageProductDependency section */
804-
741C475B25EC5DE100F1231B /* Feedbacks */ = {
794+
1A7057E6266167540070FD5D /* Feedbacks */ = {
805795
isa = XCSwiftPackageProductDependency;
806-
package = 741C475A25EC5DE100F1231B /* XCRemoteSwiftPackageReference "Feedbacks" */;
807796
productName = Feedbacks;
808797
};
809-
741C476525EC5E4C00F1231B /* FeedbacksTest */ = {
798+
1A7057E8266167950070FD5D /* FeedbacksTest */ = {
810799
isa = XCSwiftPackageProductDependency;
811-
package = 741C475A25EC5DE100F1231B /* XCRemoteSwiftPackageReference "Feedbacks" */;
812800
productName = FeedbacksTest;
813801
};
814802
/* End XCSwiftPackageProductDependency section */

Examples/Examples.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved

Lines changed: 13 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Examples/Examples/CounterApp/System/CounterApp+System.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// Created by Thibault Wittemberg on 2021-01-12.
66
//
77

8+
import Dispatch
89
import Feedbacks
910

1011
// define a namespace for this app's system
@@ -55,5 +56,5 @@ extension CounterApp.System {
5556
On(CounterApp.Events.Decrease.self, transitionTo: CounterApp.States.Decreasing(counter: state.counter.decrease(), isPaused: false))
5657
}
5758
}
58-
}
59+
}.execute(on: DispatchQueue(label: "Counter Queue"))
5960
}

Examples/Examples/GiphyApp/Features/GifDetail/System/GifDetail+System.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,7 @@ extension GifDetail.System {
3232

3333
Feedbacks {
3434
Feedback(on: GifDetail.States.Loading.self, strategy: .cancelOnNewState, perform: loadSideEffect)
35-
.execute(on: DispatchQueue(label: "Load Gif Queue"))
36-
3735
Feedback(on: GifDetail.States.TogglingFavorite.self, strategy: .cancelOnNewState, perform: toggleFavoriteSideEffect)
38-
.execute(on: DispatchQueue(label: "Toggle Favorite Queue"))
3936
}
4037
.onStateReceived {
4138
print("GifDetail: New state has been received: \($0)")
@@ -64,6 +61,6 @@ extension GifDetail.System {
6461
On(GifDetail.Events.LoadingHasFailed.self, transitionTo: GifDetail.States.Failed())
6562
}
6663
}
67-
}
64+
}.execute(on: DispatchQueue(label: "Load Gif Queue"))
6865
}
6966
}

Examples/Examples/GiphyApp/Features/GifList/System/GifList+System.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ extension GifList.System {
2626

2727
Feedbacks {
2828
Feedback(on: GifList.States.Loading.self , strategy: .cancelOnNewState, perform: loadSideEffect)
29-
.execute(on: DispatchQueue(label: "Load Gifs Queue"))
3029
}
3130
.onStateReceived {
3231
print("GifList: New state has been received: \($0)")
@@ -64,6 +63,6 @@ extension GifList.System {
6463
On(GifList.Events.Refresh.self, transitionTo: GifList.States.Loading())
6564
}
6665
}
67-
}
66+
}.execute(on: DispatchQueue(label: "Load Gifs Queue"))
6867
}
6968
}

Package.resolved

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ let package = Package(
2323
dependencies: [
2424
// Dependencies declare other packages that this package depends on.
2525
.package(url: "https://github.com/pointfreeco/combine-schedulers.git", .exact(Version("0.1.2"))),
26+
.package(url: "https://github.com/CombineCommunity/CombineExt.git", .exact(Version("1.3.0")))
2627
],
2728
targets: [
2829
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
2930
// Targets can depend on other targets in this package, and on products in packages this package depends on.
3031
.target(
3132
name: "Feedbacks",
32-
dependencies: [],
33+
dependencies: [.product(name: "CombineExt", package: "CombineExt")],
3334
path: "Sources/Feedbacks"),
3435
.testTarget(
3536
name: "FeedbacksTests",

README.md

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ In our example, one feedback takes care of increasing the volume and the other i
9696

9797
## Scheduling
9898

99-
Threading is very important to make a nice responsive application. A Scheduler is the Combine way of handling threading by switching portions of reactive streams on dispatch queues, or operation queues or RunLoops.
99+
Threading is very important to make a nice responsive application. A Scheduler is the Combine way of handling threading by switching portions of reactive streams on dispatch queues, operation queues or RunLoops.
100100

101-
The declarative syntax of Feedbacks allows to alter the behavior of side effects by simply applying modifiers (like you would do with SwiftUI to change the frame for instance). Modifying the scheduling of a side effect is as simple as calling the `.execute(on:)` modifier.
101+
The declarative syntax of Feedbacks allows to alter the behavior of a System by simply applying modifiers (like you would do with SwiftUI to change the frame for instance). Modifying the scheduling of a side effect is as simple as calling the `.execute(on:)` modifier.
102102

103103
```swift
104104
Feedbacks {
@@ -128,6 +128,52 @@ Feedbacks {
128128

129129
Both side effects will be executed on the background queue.
130130

131+
It is also applicable to the transitions:
132+
133+
```swift
134+
Transitions {
135+
From(VolumeState.self) { state in
136+
On(IncreaseEvent.self, transitionTo: VolumeState(value: state.value + 1))
137+
On(DecreaseEvent.self, transitionTo: VolumeState(value: state.value - 1))
138+
}
139+
}.execute(on: DispatchQueue(label: "A background queue"))
140+
```
141+
142+
or to the whole system:
143+
144+
```swift
145+
System {
146+
InitialState {
147+
VolumeState(value: 10)
148+
}
149+
150+
Feedbacks {
151+
Feedback(on: VolumeState.self, strategy: .continueOnNewState) { state -> AnyPublisher<Event, Never> in
152+
if state.value >= targetedVolume {
153+
return Empty().eraseToAnyPublisher()
154+
}
155+
156+
return Just(IncreaseEvent()).eraseToAnyPublisher()
157+
}
158+
159+
Feedback(on: VolumeState.self, strategy: .continueOnNewState) { state -> AnyPublisher<Event, Never> in
160+
if state.value <= targetedVolume {
161+
return Empty().eraseToAnyPublisher()
162+
}
163+
164+
return Just(DecreaseEvent()).eraseToAnyPublisher()
165+
}
166+
}
167+
168+
Transitions {
169+
From(VolumeState.self) { state in
170+
On(IncreaseEvent.self, transitionTo: VolumeState(value: state.value + 1))
171+
On(DecreaseEvent.self, transitionTo: VolumeState(value: state.value - 1))
172+
}
173+
}
174+
}.execute(on: DispatchQueue(label: "A background queue"))
175+
```
176+
131177
## Lifecycle
132178

133179
There are typical cases where a side effect consist of an asynchronous operation (like a network call). What happens if the very same side effect is called repeatedly, not waiting for the previous ones to end? Are the operations stacked? Are they cancelled when a new one is performed?
@@ -196,9 +242,9 @@ Here is a list of the supported modifiers:
196242
| Modifier | Action | Can be applied to |
197243
| -------------- | -------------- | -------------- |
198244
| `.disable(disabled:)`| The target won't be executed as long as the `disabled` condition is true | <ul align="left"><li>Transition</li><li>Transitions</li><li>Feedback</li></ul> |
199-
| `.execute(on:)`| The target will be executed on the scheduler | <ul align="left"><li>Feedbacks</li><li>Feedback</li></ul> |
200-
| `.onStateReceived(perform:)`| Execute the `perform` closure each time a new state is given as an input | <ul align="left"><li>Feedbacks</li><li>Feedback</li></ul> |
201-
| `.onEventEmitted(perform:)`| Execute the `perform` closure each time a new event is emitted | <ul align="left"><li>Feedbacks</li><li>Feedback</li></ul> |
245+
| `.execute(on:)`| The target will be executed on the scheduler | <ul align="left"><li>Transitions</li><li>Feedback</li><li>Feedbacks</li><li>System</li></ul> |
246+
| `.onStateReceived(perform:)`| Execute the `perform` closure each time a new state is given as an input | <ul align="left"><li>Feedback</li><li>Feedbacks</li></ul> |
247+
| `.onEventEmitted(perform:)`| Execute the `perform` closure each time a new event is emitted | <ul align="left"><li>Feedback</li><li>Feedbacks</li></ul> |
202248
| `.attach(to:)`| Refer to the "How to make systems communicate" section | <ul align="left"><li>System</li><li>UISystem</li></ul> |
203249
| `.uiSystem(viewStateFactory:)`| Refer to the "Using Feedbacks with SwiftUI and UIKit" section | <ul align="left"><li>System</li></ul> |
204250

File renamed without changes.

0 commit comments

Comments
 (0)