RxSwift文档翻译3 --Combination Operators

前言

本章节的介绍操作主要是是将多个观察序列合成一个观察序列

Combination Operators

  • startWith
    在源观察序列的元素之前发出元素,也可以理解为元队列的元素之前插入元素。并且每次不同的startWith发出或者插入的元素类似一种栈结构,后进先出的,但是在当前的startWith多个元素是不具有这种方式,还是按照队列的先进先出的
example("startWith") {
    let disposeBag = DisposeBag()

    Observable.of("🐶", "🐱", "🐭", "🐹")
        .startWith("1️⃣")
        .startWith("2️⃣")
        .startWith("3️⃣", "🅰️", "🅱️")
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}

// 控制台打印的结果:
--- startWith example ---
3️⃣
🅰️
🅱️
2️⃣
1️⃣
🐶
🐱
🐭
🐹
  • merger
    将多个观察序列合成为一个新的观察序列,新序列发出按照源序列发出(或者说插入,添加)元素的顺序发出
example("merge") {
    let disposeBag = DisposeBag()
    
    let subject1 = PublishSubject<String>()
    let subject2 = PublishSubject<String>()
    
    Observable.of(subject1, subject2)
        .merge()
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
    
    subject1.onNext("🅰️")
    
    subject1.onNext("🅱️")
    
    subject2.onNext("①")
    
    subject2.onNext("②")
    
    subject1.onNext("🆎")
    
    subject2.onNext("③")
}

// 控制台打印的结果:
--- merge example ---
🅰️
🅱️
①
②
🆎
③
  • ** zip **
    和merger有点相似,也是将最多8个序列合成一个序列,但是zip可以将两个序列的对应顺序的元素进行合并,如果某个序列相应的顺序没有元素,则该顺序的所有序列的元素不会进行合并
    上文翻译的顺序我自认为可以理解为索引,比如队列a b c,只有a、b、c这三个序列的索引n都有元素的之后才会将三者进行合并,只要一个序列的索引n没有元素就,那么该索引n下的元素均不合并
example("zip") {
    let disposeBag = DisposeBag()
    
    let stringSubject = PublishSubject<String>()
    let intSubject = PublishSubject<Int>()
    
    Observable.zip(stringSubject, intSubject) { stringElement, intElement in
        "\(stringElement) \(intElement)"
        }
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
    
    stringSubject.onNext("🅰️")
    stringSubject.onNext("🅱️")
    
    intSubject.onNext(1)
    
    intSubject.onNext(2)
    
    stringSubject.onNext("🆎")
    intSubject.onNext(3)
}
// 控制台打印的结果:
--- zip example ---
🅰️ 1
🅱️ 2
🆎 3

// 本文不作者修改的程序1
         example("zip") {
            let disposeBag = DisposeBag()
            
            let stringSubject = PublishSubject<String>()
            let intSubject = PublishSubject<Int>()
            
            Observable.zip(stringSubject, intSubject) { stringElement, intElement in
                "\(stringElement) \(intElement)"
                }
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
            
            stringSubject.onNext("🅰️")
            stringSubject.onNext("🅱️")
            
            intSubject.onNext(1)
            
            intSubject.onNext(2)
            
            stringSubject.onNext("🆎")
            intSubject.onNext(3)
            // 这里添加一个事件元素
            intSubject.onNext(4)
        }

// 控制台打印的结果:
--- zip example ---
🅰️ 1
🅱️ 2
🆎 3
  
// 本文不作者修改的程序2
example("zip") {
            let disposeBag = DisposeBag()
            
            let stringSubject = PublishSubject<String>()
            let intSubject = PublishSubject<Int>()
            let intSubject2 = PublishSubject<Int>()
            
            Observable.zip(stringSubject, intSubject, intSubject2) { stringElement, intElement, intSubject2 in
                "\(stringElement) \(intElement)"
                }
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
            
            stringSubject.onNext("🅰️")
            stringSubject.onNext("🅱️")
            
            intSubject.onNext(1)
            
            intSubject.onNext(2)
            
            stringSubject.onNext("🆎")
            intSubject.onNext(3)
            
            intSubject.onNext(4)
        }  
// 控制台打印的结果:
--- zip example ---

修改程序解释:
在官方的演示程序后面我添加了两个修改的程序
1.intSubject.onNext(4),添加这一句,但是控制台没有打印,因为stringSubject没有事件元素与其配对,故没有打印
2.多添加一个观察序列intSubject2,但是由于intSubject2并没有添加任何事件元素,这意味着三个观察序列每次所以都不能成功配对,故控制台打印为空

  • combineLatest
    合并最多8个观察者序列,此操作是将每个序列最新的元素进行合并,而且在某个序列有新元素添加的时候也会执行同样的合并操作,并且新元素也会找其他序列的最新的元素进行和并购,引用官方的一张演示图,能更好的理解此操作
官方演示图
example("combineLatest") {
            let disposeBag = DisposeBag()
            
            let stringSubject = PublishSubject<String>()
            let intSubject = PublishSubject<Int>()
            
            Observable.combineLatest(stringSubject, intSubject) { stringElement, intElement in
                " \(intElement)\(stringElement)"
                }
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
            intSubject.onNext(1) 

            stringSubject.onNext("A")
            stringSubject.onNext("B")

            intSubject.onNext(2)
            stringSubject.onNext("C")
            stringSubject.onNext("D")
            
            intSubject.onNext(3)
            intSubject.onNext(4)
            intSubject.onNext(5)
        }

// 控制台打印的结果:
--- combineLatest example ---
 1A
 1B
 2B
 2C
 2D
 3D
 4D
 5D

combineLatest同样适用Array(或者其他的观察者序列的集合)的操作,但是要求序列集合类型必须一致,即Observer<T>的T是一种类型,否则编译前就会报错

类型不一致报错

example("Array.combineLatest") {
    let disposeBag = DisposeBag()
    
    let stringObservable = Observable.just("❤️")
    let fruitObservable = Observable.from(["🍎", "🍐", "🍊"])
    let animalObservable = Observable.of("🐶", "🐱", "🐭", "🐹")
    
    Observable.combineLatest([stringObservable, fruitObservable, animalObservable]) {
            "\($0[0]) \($0[1]) \($0[2])"
        }
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
}

// 控制台打印的结果:
--- Array.combineLatest example ---
❤️ 🍎 🐶
❤️ 🍐 🐶
❤️ 🍐 🐱
❤️ 🍊 🐱
❤️ 🍊 🐭
❤️ 🍊 🐹

  • switchLatest
    官方翻译为:将Observable序列发射的元素转换为Observable序列,并从最近的内部Observable序列中发出元素

本文作者注:官方的解释较为模糊,个人理解为switch是一个切换功能,用在序列元素也是一个观察序列的场景,假设将序列的序列定义oss,将序列定义为os,在oss的元素值设置为os1的时候,则响应os1的事件元素,当oss的元素值设置为os2的时候,此时响应os2的事件元素,此时os1即便有事件元素发出也不响应,当oss的元素值再切换到os1的时候,则再去相应os1的事件元素

/*:
 > Because the `combineLatest` variant that takes a collection passes an array of values to the selector function, it requires that all source `Observable` sequences are of the same type.
 ----
 ## `switchLatest`
 Transforms the elements emitted by an `Observable` sequence into `Observable` sequences, and emits elements from the most recent inner `Observable` sequence. [More info](http://reactivex.io/documentation/operators/switch.html)
 ![](http://upload-images.jianshu.io/upload_images/954728-c0141794880b5a6f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
 */
example("switchLatest") {
    let disposeBag = DisposeBag()
    
    let subject1 = BehaviorSubject(value: "⚽️")
    let subject2 = BehaviorSubject(value: "🍎")
    
    let variable = Variable(subject1)
        
    variable.asObservable()
        .switchLatest()
        .subscribe(onNext: { print($0) })
        .disposed(by: disposeBag)
    
    subject1.onNext("🏈")
    subject1.onNext("🏀")
    
    variable.value = subject2
    
    subject1.onNext("⚾️")
    
    subject2.onNext("🍐")
}

// 控制台打印的结果:
--- switchLatest example ---
⚽️
🏈
🏀
🍎
🍐

此官方实例中⚾️没有打印出来,因为variable(即oss)将值切换为subject2(即os2)之后,subject1(即os1)的值⚾️对subject2没有作用,故Variable不相应⚾️,为了让大家更易于理解switchLatest,我在官方的代码最后加一句variable.value = subject1,即将variable的值切换回subject1,则subjec1的事件元素⚾️将会被相应:

example("switchLatest") {
            let disposeBag = DisposeBag()
            
            let subject1 = BehaviorSubject(value: "⚽️")
            let subject2 = BehaviorSubject(value: "🍎")
            
            let variable = Variable(subject1)
            
            variable.asObservable()
                .switchLatest()
                .subscribe(onNext: { print($0) })
                .disposed(by: disposeBag)
            
            subject1.onNext("🏈")
            subject1.onNext("🏀")
            
            variable.value = subject2
            
            subject1.onNext("⚾️")
            
            subject2.onNext("🍐")
            
            variable.value = subject1
        }
// 控制台打印的结果:
--- switchLatest example ---
⚽️
🏈
🏀
🍎
🍐
⚾️

下一篇: RxSwift文档翻译4 -- Transforming Operators

推荐阅读更多精彩内容