Adds flatMapLatest to Driver unit.

This commit is contained in:
Krunoslav Zaher 2015-11-15 23:21:39 +01:00
parent 65cc061b17
commit 7d3387989d
7 changed files with 87 additions and 26 deletions

View File

@ -190,13 +190,12 @@ Writing all of this and properly testing it would be tedious. This is that same
searchTextField.rx_text
.throttle(0.3, MainScheduler.sharedInstance)
.distinctUntilChanged()
.map { query in
.flatMapLatest { query in
API.getSearchResults(query)
.retry(3)
.startWith([]) // clears results on new search term
.catchErrorJustReturn([])
}
.switchLatest()
.subscribeNext { results in
// bind to ui
}

View File

@ -63,6 +63,27 @@ extension DriverConvertibleType where E : DriverConvertibleType {
}
}
extension DriverConvertibleType {
/**
Projects each element of an observable sequence into a new sequence of observable sequences and then
transforms an observable sequence of observable sequences into an observable sequence producing values only from the most recent observable sequence.
It is a combination of `map` + `switchLatest` operator
- parameter selector: A transform function to apply to each element.
- returns: An observable sequence whose elements are the result of invoking the transform function on each element of source producing an
Observable of Observable sequences and that at any point in time produces the elements of the most recent inner observable sequence that has been received.
*/
@warn_unused_result(message="http://git.io/rxs.uo")
public func flatMapLatest<R>(selector: (E) -> Driver<R>)
-> Driver<R> {
let source: Observable<R> = self
.asObservable()
.flatMapLatest(selector)
return Driver<R>(source)
}
}
extension DriverConvertibleType {
/**

View File

@ -112,7 +112,7 @@ func observeWeaklyKeyPathFor(
// KVO recursion for value changes
return propertyObservable
.map { (nextTarget: AnyObject?) -> Observable<AnyObject?> in
.flatMapLatest { (nextTarget: AnyObject?) -> Observable<AnyObject?> in
if nextTarget == nil {
return just(nil)
}
@ -142,7 +142,6 @@ func observeWeaklyKeyPathFor(
return nextElementsObservable
}
}
.switchLatest()
}
#endif

View File

@ -83,7 +83,7 @@ class GitHubSearchRepositoriesViewController: ViewController, UITableViewDelegat
let searchResult = searchBar.rx_text.asDriver()
.throttle(0.3, $.mainScheduler)
.distinctUntilChanged()
.map { query -> Driver<RepositoriesState> in
.flatMapLatest { query -> Driver<RepositoriesState> in
if query.isEmpty {
return Drive.just(RepositoriesState.empty)
} else {
@ -91,7 +91,6 @@ class GitHubSearchRepositoriesViewController: ViewController, UITableViewDelegat
.asDriver(onErrorJustReturn: RepositoriesState.empty)
}
}
.switchLatest()
searchResult
.map { $0.serviceState }

View File

@ -169,10 +169,9 @@ class GitHubSignupViewController : ViewController {
let signupSampler = signupOutlet.rx_tap
let usernameValidation = username
.map { username in
.flatMapLatest { username in
return validationService.validateUsername(username)
}
.switchLatest()
.shareReplay(1)
let passwordValidation = password
@ -188,10 +187,9 @@ class GitHubSignupViewController : ViewController {
let signingProcess = combineLatest(username, password) { ($0, $1) }
.sampleLatest(signupSampler)
.map { (username, password) in
.flatMapLatest { (username, password) in
return API.signup(username, password: password)
}
.switchLatest()
.startWith(SignupState.InitialState)
.shareReplay(1)

View File

@ -31,14 +31,13 @@ class SearchViewModel {
self.rows = searchText
.throttle(0.3, $.mainScheduler)
.distinctUntilChanged()
.map { query in
.flatMapLatest { query in
API.getSearchResults(query)
.retry(3)
.retryOnBecomesReachable([], reachabilityService: ReachabilityService.sharedReachabilityService)
.startWith([]) // clears results on new search term
.asDriver(onErrorJustReturn: [])
}
.switchLatest()
.map { results in
results.map {
SearchResultViewModel(

View File

@ -89,7 +89,7 @@ extension DriverTest {
}
}
// conversions
// MARK: conversions
extension DriverTest {
func testAsDriver_onErrorJustReturn() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -145,7 +145,7 @@ extension DriverTest {
}
}
// map
// MARK: map
extension DriverTest {
func testAsDriver_map() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -169,7 +169,7 @@ extension DriverTest {
}
// filter
// MARK: filter
extension DriverTest {
func testAsDriver_filter() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -193,7 +193,7 @@ extension DriverTest {
}
// switch latest
// MARK: switch latest
extension DriverTest {
func testAsDriver_switchLatest() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Driver<Int>>()
@ -232,7 +232,53 @@ extension DriverTest {
}
}
// doOn
// MARK: flatMapLatest
extension DriverTest {
func testAsDriver_flatMapLatest() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
let hotObservable1 = MainThreadPrimitiveHotObservable<Int>()
let hotObservable2 = MainThreadPrimitiveHotObservable<Int>()
let errorHotObservable = MainThreadPrimitiveHotObservable<Int>()
let drivers: [Driver<Int>] = [
hotObservable1.asDriver(onErrorJustReturn: -2),
hotObservable2.asDriver(onErrorJustReturn: -3),
errorHotObservable.asDriver(onErrorJustReturn: -4),
]
let driver = hotObservable.asDriver(onErrorJustReturn: 2).flatMapLatest { drivers[$0] }
let results = subscribeTwiceOnBackgroundSchedulerAndOnlyOneSubscription(driver) {
XCTAssertTrue(hotObservable.subscriptions == [SubscribedToHotObservable])
hotObservable.on(.Next(0))
hotObservable1.on(.Next(1))
hotObservable1.on(.Next(2))
hotObservable1.on(.Error(testError))
hotObservable.on(.Next(1))
hotObservable2.on(.Next(10))
hotObservable2.on(.Next(11))
hotObservable2.on(.Error(testError))
hotObservable.on(.Error(testError))
errorHotObservable.on(.Completed)
hotObservable.on(.Completed)
XCTAssertTrue(hotObservable.subscriptions == [UnsunscribedFromHotObservable])
}
XCTAssertEqual(results, [
1, 2, -2,
10, 11, -3
])
}
}
// MARK: doOn
extension DriverTest {
func testAsDriver_doOn() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -261,7 +307,7 @@ extension DriverTest {
}
}
// distinct until change
// MARK: distinct until change
extension DriverTest {
func testAsDriver_distinctUntilChanged1() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -342,7 +388,7 @@ extension DriverTest {
}
// flat map
// MARK: flat map
extension DriverTest {
func testAsDriver_flatMap() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -366,7 +412,7 @@ extension DriverTest {
}
// merge
// MARK: merge
extension DriverTest {
func testAsDriver_merge() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -409,7 +455,7 @@ extension DriverTest {
}
}
// debounce
// MARK: debounce
extension DriverTest {
func testAsDriver_debounce() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -445,7 +491,7 @@ extension DriverTest {
}
// scan
// MARK: scan
extension DriverTest {
func testAsDriver_scan() {
let hotObservable = BackgroundThreadPrimitiveHotObservable<Int>()
@ -469,7 +515,7 @@ extension DriverTest {
}
// concat
// MARK: concat
extension DriverTest {
func testAsDriver_concat() {
let hotObservable1 = BackgroundThreadPrimitiveHotObservable<Int>()
@ -498,7 +544,7 @@ extension DriverTest {
}
}
// combine latest
// MARK: combine latest
extension DriverTest {
func testAsDriver_combineLatest_array() {
let hotObservable1 = BackgroundThreadPrimitiveHotObservable<Int>()
@ -553,7 +599,7 @@ extension DriverTest {
}
}
// zip
// MARK: zip
extension DriverTest {
func testAsDriver_zip_array() {
let hotObservable1 = BackgroundThreadPrimitiveHotObservable<Int>()
@ -608,7 +654,7 @@ extension DriverTest {
}
}
// withLatestFrom
// MARK: withLatestFrom
extension DriverTest {
func testAsDriver_withLatestFrom() {
let hotObservable1 = BackgroundThreadPrimitiveHotObservable<Int>()