Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conveniences for creating state machine as Property. #11

Merged
merged 2 commits into from
Oct 19, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 8 additions & 15 deletions Example/PaginationViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ final class PaginationViewModel {
private let nearBottomObserver: Signal<Void, NoError>.Observer
private let retryObserver: Signal<Void, NoError>.Observer

private let stateProperty: Property<State>
let movies: Property<[Movie]>
let errors: Property<NSError?>
let refreshing: Property<Bool>
Expand All @@ -88,24 +89,16 @@ final class PaginationViewModel {
Feedbacks.retryFeedback(for: retrySignal),
Feedbacks.retryPagingFeedback()
]
let initialState = State.initial
let stateProducer = SignalProducer.system(initial: initialState,
reduce: State.reduce,
feedbacks: feedbacks)
.observe(on: QueueScheduler.main)

let stateProperty = Property<State>(initial: initialState, then: stateProducer)
self.stateProperty = Property(initial: State.initial,
reduce: State.reduce,
feedbacks: feedbacks)

self.movies = Property<[Movie]>.init(initial: [], then: stateProperty.signal.filterMap {
$0.newMovies
})
self.movies = Property<[Movie]>(initial: [],
then: stateProperty.producer.filterMap { $0.newMovies })

self.errors = Property<NSError?>.init(initial: nil, then: stateProperty.producer.map {
$0.lastError
})
self.refreshing = stateProperty.map {
$0.isRefreshing
}
self.errors = stateProperty.map { $0.lastError }
self.refreshing = stateProperty.map { $0.isRefreshing }
self.nearBottomObserver = nearBottomObserver
self.retryObserver = retryObserver
}
Expand Down
10 changes: 5 additions & 5 deletions Example/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class ViewController: UIViewController {
}

final class ViewModel {
private let state: Property<Int>
let counter: Property<String>

init(increment: Signal<Void, NoError>, decrement: Signal<Void, NoError>) {
Expand All @@ -56,12 +57,11 @@ final class ViewModel {
return decrement.map { _ in Event.decrement }
}

let state = SignalProducer.system(initial: 0,
reduce: IncrementReducer.reduce,
feedbacks: incrementFeedback, decrementFeedback)
.map(String.init)
self.state = Property(initial: 0,
reduce: IncrementReducer.reduce,
feedbacks: incrementFeedback, decrementFeedback)

self.counter = Property(initial: "", then: state)
self.counter = state.map(String.init)

}
}
Expand Down
5 changes: 5 additions & 0 deletions ReactiveFeedback.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
5898B6D11F97ADDD005EEAEC /* SystemTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5898B6D01F97ADDD005EEAEC /* SystemTests.swift */; };
9A4CCB0B1F95D5CA00ACF758 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A4CCB0C1F95D5CA00ACF758 /* Nimble.framework */; };
9A4CCB0D1F95D5D500ACF758 /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9A4CCB0C1F95D5CA00ACF758 /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9AD5D42D1F97375E00E6AE5A /* Property+System.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AD5D42C1F97375E00E6AE5A /* Property+System.swift */; };
9AE181B91F95A71B00A07551 /* ReactiveFeedbackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AE181B81F95A71B00A07551 /* ReactiveFeedbackTests.swift */; };
9AE181BB1F95A71B00A07551 /* ReactiveFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 25CC87AE1F92855300A6EBFC /* ReactiveFeedback.framework */; };
9AE181C21F95A77500A07551 /* ReactiveSwift.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9AFA212A1F95135B001DBF7C /* ReactiveSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9AE181C31F95A77500A07551 /* Result.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9AFA212B1F95135B001DBF7C /* Result.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -98,6 +100,7 @@
25E1D2371F56091A00D90192 /* PaginationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PaginationViewController.swift; sourceTree = "<group>"; };
5898B6D01F97ADDD005EEAEC /* SystemTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SystemTests.swift; sourceTree = "<group>"; };
9A4CCB0C1F95D5CA00ACF758 /* Nimble.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Nimble.framework; sourceTree = BUILT_PRODUCTS_DIR; };
9AD5D42C1F97375E00E6AE5A /* Property+System.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Property+System.swift"; sourceTree = "<group>"; };
9AE181B61F95A71B00A07551 /* ReactiveFeedbackTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReactiveFeedbackTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
9AE181BA1F95A71B00A07551 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
9AFA21251F9511A5001DBF7C /* ReactiveFeedback.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = ReactiveFeedback.podspec; sourceTree = "<group>"; };
Expand Down Expand Up @@ -150,6 +153,7 @@
children = (
A95097E70D3CBFF05FA7B8CC /* Feedback.swift */,
A9509880213192F0D80EC2B3 /* SignalProducer+System.swift */,
9AD5D42C1F97375E00E6AE5A /* Property+System.swift */,
25CC87B11F92855300A6EBFC /* Info.plist */,
);
path = ReactiveFeedback;
Expand Down Expand Up @@ -359,6 +363,7 @@
files = (
A9509BE4551098F4A5503820 /* Feedback.swift in Sources */,
A950943401765BB90FA846B2 /* SignalProducer+System.swift in Sources */,
9AD5D42D1F97375E00E6AE5A /* Property+System.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
28 changes: 28 additions & 0 deletions ReactiveFeedback/Property+System.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import ReactiveSwift

extension Property {
public convenience init<Event>(
initial: Value,
scheduler: Scheduler = QueueScheduler.main,
reduce: @escaping (Value, Event) -> Value,
feedbacks: [Feedback<Value, Event>]
) {
let state = MutableProperty(initial)
state <~ SignalProducer.system(initial: initial,
scheduler: scheduler,
reduce: reduce,
feedbacks: feedbacks)
.skip(first: 1)

self.init(capturing: state)
}

public convenience init<Event>(
initial: Value,
scheduler: Scheduler = QueueScheduler.main,
reduce: @escaping (Value, Event) -> Value,
feedbacks: Feedback<Value, Event>...
) {
self.init(initial: initial, scheduler: scheduler, reduce: reduce, feedbacks: feedbacks)
}
}
11 changes: 4 additions & 7 deletions ReactiveFeedback/SignalProducer+System.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ extension SignalProducer where Error == NoError {
feedbacks: [Feedback<Value, Event>]
) -> SignalProducer<Value, NoError> {
return SignalProducer.deferred {
let (state, observer) = Signal<Value, NoError>.pipe()
let (state, stateObserver) = Signal<Value, NoError>.pipe()

let events = feedbacks.map { feedback in
return feedback.events(scheduler, state)
Expand All @@ -19,7 +19,7 @@ extension SignalProducer where Error == NoError {
return SignalProducer<Event, NoError>(Signal.merge(events))
.scan(initial, reduce)
.prefix(value: initial)
.on(value: observer.send(value:))
.on(value: stateObserver.send(value:))
}
}

Expand All @@ -30,11 +30,8 @@ extension SignalProducer where Error == NoError {
) -> SignalProducer<Value, Error> {
return system(initial: initial, reduce: reduce, feedbacks: feedbacks)
}
}

extension SignalProducerProtocol {
static func deferred(_ signalProducerFactory: @escaping () -> SignalProducer<Value, Error>) -> SignalProducer<Value, Error> {
return SignalProducer<Void, Error>(value: ())
.flatMap(.merge, signalProducerFactory)
private static func deferred(_ producer: @escaping () -> SignalProducer<Value, Error>) -> SignalProducer<Value, Error> {
return SignalProducer { $1 += producer().start($0) }
}
}