(七)RxSwift之变换操作符(transforming)

830 阅读2分钟

对事件序列中的事件(序列)进行变换,使得其转变成不同的事件(序列)

操作符 描述
amb 传入多个 Observables 到 amb 操作符时,它将取第一个产生事件的那个 Observable
buffer 周期性的将缓存的元素集合发送出来(当元素达到某个数量,或者经过了特定的时间)
window 周期性的将实时的元素集合发送出来
groupBy 将元素通过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来
scan (累加器)将结果作为参数填入到第二个元素的应用函数中,创建第二个元素
map 将源 Observable 的每个元素应用闭包表达式的转换方法,然后返回含有转换结果的 Observable
flatMap 将源 Observable 的每个元素应用闭包表达式的转换方法,转换后,即接收旧的,也接收新的
flatMapFirst 将源 Observable 的每一个元素应用一个转换方法,只接收旧的Observable
flatMapLatest 将源 Observable 的每一个元素应用一个转换方法,转换后,只接收新的Observable,忽略旧的
concatMap 将源 Observable 的每一个元素应用一个转换方法,当第一个完成后,接收第二个
  • amb

在多个源 Observables 中, 取第一个发出元素或产生事件的 Observable,然后只发出它的元素,忽略掉其他的 Observables。

示例:

let firstObservable = Observable.just(0)
let seconedObservable = Observable.just(1)
let thirdObservable = Observable.just(2)

Observable<Int>.amb([firstObservable, seconedObservable, thirdObservable])
    .subscribe(
        onNext: { print($0) },
        onError: { (error) in
            print(error)
        }, onCompleted: {
            print("完成")
        }).disposed(by: disposeBag)
//输出:0 完成 
'那个先发出事件就接收那个。'
  • buffer

缓存元素,然后将缓存的元素集合,周期性的发出来

示例:

let subject = PublishSubject<Int>()
subject.buffer(timeSpan: DispatchTimeInterval.seconds(1), count: 3, scheduler: MainScheduler())
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

subject.onNext(1)
subject.onNext(2)
subject.onNext(3)

subject.onNext(4)
subject.onNext(5)
subject.onNext(6)

subject.onNext(7)
//输出:
[1, 2, 3]
[4, 5, 6]
间隔5S以后
[7]
间隔5S以后
[]
间隔5S以后
[]
···
'不够3个元素,间隔时间内等一下'
  • window

将 Observable 分解为多个子 Observable,周期性的将子 Observable 发出来

示例:

let subject = PublishSubject<Int>()
subject
    .debug()
    .window(timeSpan: DispatchTimeInterval.seconds(5), count: 3, scheduler: MainScheduler())
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

subject.onNext(1)
subject.onNext(2)
subject.onNext(3)

subject.onNext(4)
subject.onNext(5)
subject.onNext(6)

subject.onNext(7)
//输出:
RxSwift.AddRef<Swift.Int>
2019-10-23 11:54:49.050: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> subscribed
2019-10-23 11:54:49.052: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> Event next(1)
2019-10-23 11:54:49.052: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> Event next(2)
2019-10-23 11:54:49.052: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> Event next(3)
RxSwift.AddRef<Swift.Int>
2019-10-23 11:54:49.052: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> Event next(4)
2019-10-23 11:54:49.052: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> Event next(5)
2019-10-23 11:54:49.052: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> Event next(6)
RxSwift.AddRef<Swift.Int>
2019-10-23 11:54:49.052: MHigherOrderFunctionsViewController.swift:275 (testWindow()) -> Event next(7)
间隔5S以后
RxSwift.AddRef<Swift.Int>
间隔5S以后
RxSwift.AddRef<Swift.Int>
'一起发出所有元素'

window 操作符和 buffer 十分相似,buffer 周期性的将缓存的元素集合发送出来,而 window 周期性的将元素集合以 Observable 的形态发送出来。 buffer 要等到元素搜集完毕后,才会发出元素序列。而 window 可以实时发出元素序列。

  • groupBy

groupBy 操作符将源 Observable 分解为多个子 Observable,然后将这些子 Observable 发送出来。通过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来。

示例:将奇数偶数分成两组

Observable<Int>.of(0, 1 ,2 ,3 ,4, 5)
    .groupBy(keySelector: { (element) -> String in
        return element % 2 == 0 ? "偶数" : "奇数"
    })
    .subscribe { (event) in
        switch event {
        case .next(let group):
            group.asObservable().subscribe({ (event) in
                print("key:\(group.key)    event:\(event)")
            })
                .disposed(by: self.disposeBag)
        default:
            print("")
        }
    }
    .disposed(by: disposeBag)
}
输出:
key:偶数    event:next(0)
key:奇数    event:next(1)
key:偶数    event:next(2)
key:奇数    event:next(3)
key:偶数    event:next(4)
key:奇数    event:next(5)
key:奇数    event:next(7)
key:偶数    event:completed
key:奇数    event:completed
'以键值的方式将元素分组'
  • scan

从初始就带有一个默认值开始,然后对可观察序列发出的每个元素应用累加器闭包,并以单个元素可观察序列的形式返回每个中间结果

示例:

Observable.of(10, 100, 1000)
    .scan(2) { aggregateValue, newValue in
        aggregateValue + newValue //10 + 2 , 100 + 10 + 2 , 1000 + 100 + 2
}
.subscribe(onNext: { print($0, terminator: " ") })
.disposed(by: disposeBag)
//输出:12 112 1112
'累加器(accumulator)每次都用到上一个元素'
  • map

转换闭包应用于可观察序列发出的元素,并返回转换后的元素的新可观察序列。

示例:

let  ob = Observable.of(1, 2, 3, 4)
ob.map { (number) -> Int in
    return number + 2
}
.subscribe {
    print($0, terminator: " ")
}
.disposed(by: disposeBag)
输出:next(3) next(4) next(5) next(6) completed 
'将源序列经过表达式变成新的序列(函数式)'
  • flatMap

将可观察序列发射的元素转换为可观察序列,并将两个可观察序列的发射合并为一个可观察序列。当 Observable 的元素本身拥有其他的 Observable 时,可以将所有子 Observables 的元素发送出来。

示例:

struct MPlayer {
    init(score: Int) {
        self.score = BehaviorSubject(value: score)
    }
    let score: BehaviorSubject<Int>
}
let boy = MPlayer(score: 100)
let girl = MPlayer(score: 90)
let player = BehaviorSubject(value: boy)

player.asObservable()
    .flatMap{$0.score.asObservable()}// 本身score就是序列 模型就是序列中的序列
    .subscribe(onNext: { print($0, terminator: " ") })
    .disposed(by: disposeBag)
boy.score.onNext(60)
player.onNext(girl)
boy.score.onNext(50)
boy.score.onNext(40)  
girl.score.onNext(10)
girl.score.onNext(0)
//输出:100 60 90 50 40 10 0
'转换后同时接收 boy 和 girl'
  • flatMapFirst

将源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。只接收旧的 Observables 发出它的元素。 示例:

let boy = MPlayer(score: 100)
let girl = MPlayer(score: 90)
let player = BehaviorSubject(value: boy)

player.asObservable()
    .flatMapFirst{$0.score.asObservable()}// 本身score就是序列 模型就是序列中的序列
    .subscribe(onNext: { print($0, terminator: " ") })
    .disposed(by: disposeBag)
boy.score.onNext(60)
player.onNext(girl)
boy.score.onNext(50)
boy.score.onNext(40)
girl.score.onNext(10)
girl.score.onNext(0)
//输出:100 60 50 40 
'只接收boy'    
  • flatMapLatest

将源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。一旦转换出一个新的 Observable,就只发出它的元素,旧的 Observables 的元素将被忽略掉。

示例:

let boy = MPlayer(score: 100)
let girl = MPlayer(score: 90)
let player = BehaviorSubject(value: boy)

player.asObservable()
    .flatMapLatest{$0.score.asObservable()}// 本身score就是序列 模型就是序列中的序列
    .subscribe(onNext: { print($0, terminator: " ") })
    .disposed(by: disposeBag)
boy.score.onNext(60)
player.onNext(girl)
boy.score.onNext(50)
boy.score.onNext(40) 
girl.score.onNext(10)
girl.score.onNext(0)
//输出:100 60 90 10 0
'转换后只接收 girl'

flatMap转换后会接收新的和旧的发出元素,flatMapFirst只接受旧的, flatMapLatest转换后则只接收新的,忽略旧的。

  • concatMap

将源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。然后让这些 Observables 按顺序的发出元素,当前一个 Observable 元素发送完毕后,后一个 Observable 才可以开始发出元素。 等待前一个 Observable 产生完成事件后,才对后一个 Observable 进行订阅。

示例:

let subject1 = BehaviorSubject(value: 100)
let subject2 = BehaviorSubject(value: 90)

let variable = BehaviorSubject(value: subject1)
variable.asObservable()
    .concatMap { $0 }
    .subscribe { print($0, terminator: " ") }
    .disposed(by: disposeBag)

subject1.onNext(60)
subject1.onNext(50)

variable.onNext(subject2)

subject2.onNext(40)//被忽略
subject2.onNext(30)

subject1.onCompleted()

subject2.onNext(20)
//输出:next(100) next(60) next(50) next(30) next(20)
'subject1 完成后接收 subject2'