Skip to content

Commit e30f6e4

Browse files
committed
Add pause and resume API's to Loop
On some scenarios, it's useful to "pause" the `Loop` so that we stop processing events for some reason (e.g. to stop a `Loop` backed Service). Following the same reasoning, it becomes necessary to have a "resume" mechanism so that the Loop starts processing events again. Given `Loop` now starts automatically and `stop` is designed as a tear down mechanism to be used on dealloc and dispose all observations, some new API's are required so that we can unplug/replug feedbacks to achieve the above mentioned pause/resume behavior. ## Changes - Create new `unplugFeedbacks` and `replugFeedbacks` API's in `Floodgate`, which disposes feedbacks observations and restores them, respectively. Floodgate now retains the feedbacks passed in on `bootstrap` to use them on `replugFeedbacks`. - Add `pause` and `resume` API's to `LoopBoxBase`. - Implement `pause` and `resume` API's in `RootLoopBox`, which unplug and replug the feedbacks on the `Floodgate`, respectively. - Implement `pause` and `resume` API's in `ScopedLoopBox`, which forward the calls to their root, respectively.
1 parent 49404fc commit e30f6e4

File tree

4 files changed

+50
-3
lines changed

4 files changed

+50
-3
lines changed

Loop.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
1616
s.watchos.deployment_target = '2.0'
1717
s.tvos.deployment_target = '9.0'
1818
s.source = { :git => "https://github.com/ReactiveCocoa/Loop.git", :tag => "#{s.version}" }
19-
s.source_files = "Loop/*.{swift}"
19+
s.source_files = "Loop/**/*.{swift}"
2020

2121
s.cocoapods_version = ">= 1.7.0"
2222
s.swift_versions = ["5.0", "5.1"]

Loop/Floodgate.swift

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ final class Floodgate<State, Event>: FeedbackEventConsumer<Event> {
2929

3030
private let queue = Atomic(QueueState())
3131
private let reducer: (inout State, Event) -> Void
32-
private let feedbackDisposables = CompositeDisposable()
32+
private var feedbacks: [Loop<State, Event>.Feedback] = []
33+
private var feedbackDisposables = CompositeDisposable()
3334

3435
init(state: State, reducer: @escaping (inout State, Event) -> Void) {
3536
self.state = state
@@ -40,7 +41,25 @@ final class Floodgate<State, Event>: FeedbackEventConsumer<Event> {
4041
dispose()
4142
}
4243

43-
func bootstrap(with feedbacks: [FeedbackLoop<State, Event>.Feedback]) {
44+
func bootstrap(with feedbacks: [Loop<State, Event>.Feedback]) {
45+
self.feedbacks = feedbacks
46+
47+
for feedback in feedbacks {
48+
// Pass `producer` which has replay-1 semantic.
49+
feedbackDisposables += feedback.events(producer, self)
50+
}
51+
52+
reducerLock.perform {
53+
drainEvents()
54+
}
55+
}
56+
57+
func unplugFeedbacks() {
58+
feedbackDisposables.dispose()
59+
feedbackDisposables = CompositeDisposable()
60+
}
61+
62+
func replugFeedbacks() {
4463
for feedback in feedbacks {
4564
// Pass `producer` which has replay-1 semantic.
4665
feedbackDisposables += feedback.events(producer, self)

Loop/LoopBox.swift

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ internal class ScopedLoopBox<RootState, RootEvent, ScopedState, ScopedEvent>: Lo
4242
event: { [eventTransform] in eventTransform(event($0)) }
4343
)
4444
}
45+
46+
override func pause() {
47+
root.pause()
48+
}
49+
50+
override func resume() {
51+
root.resume()
52+
}
4553
}
4654

4755
internal class RootLoopBox<State, Event>: LoopBoxBase<State, Event> {
@@ -81,6 +89,14 @@ internal class RootLoopBox<State, Event>: LoopBoxBase<State, Event> {
8189
ScopedLoopBox(root: self, value: scope, event: event)
8290
}
8391

92+
override func pause() {
93+
floodgate.unplugFeedbacks()
94+
}
95+
96+
override func resume() {
97+
floodgate.replugFeedbacks()
98+
}
99+
84100
func start(with feedbacks: [Loop<State, Event>.Feedback]) {
85101
floodgate.bootstrap(with: feedbacks + [input.feedback])
86102
}
@@ -113,6 +129,10 @@ internal class LoopBoxBase<State, Event> {
113129
) -> LoopBoxBase<S, E> {
114130
subclassMustImplement()
115131
}
132+
133+
func pause() { subclassMustImplement() }
134+
135+
func resume() { subclassMustImplement() }
116136
}
117137

118138
@inline(never)

Loop/Public/Loop.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ public final class Loop<State, Event> {
5353
box: box.scoped(to: scope, event: event)
5454
)
5555
}
56+
57+
public func pause() {
58+
box.pause()
59+
}
60+
61+
public func resume() {
62+
box.resume()
63+
}
5664
}
5765

5866
extension Loop {

0 commit comments

Comments
 (0)