RxSwfit 学习笔记(八)其他操作符,delay、materialize、timeout、ignoreElements等

1,628 阅读3分钟

这篇主要介绍在《RxSwift 中文文档》中,未被分类的操作符。

delay

顾名思义,就是延时发送。
将产生的每一个元素,拖延一段时间后再发出。

案例

class EightViewController: UIViewController {

    let disposeBag = DisposeBag()

    
    override func viewDidLoad() {
        super.viewDidLoad()

        Observable.just("延迟发送出来的元素")
            .delay(.seconds(3), scheduler: MainScheduler.instance) //元素延迟3秒才发出
            .subscribe(onNext: { print($0) })
            .disposed(by: disposeBag)
    }
}

注意:用delay的时候,disposeBag需要是一个属性,不能是一个临时变量,否则将会失效

delaySubscription

这个用起来跟delay几乎一模一样,但是本质上的区别是

delay是延时发送
delaySubscription是延时订阅
案例

Observable.just("这是延时订阅")
    .delaySubscription(.seconds(3), scheduler: MainScheduler.instance) //延迟3秒才开始订阅
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

materialize

将序列产生的事件,转换成元素

通常,一个有限的 Observable 将产生零个或者多个 onNext 事件,然后产生一个 onCompleted 或者 onError 事件。

materialize 操作符将 Observable 产生的这些事件全部转换成元素,然后发送出来。

不好意会,我们看下面两个案例对比

Observable.just("这是materialize")
    .materialize()
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
/*
输出结果:
next(这是materialize)
completed    
*/
Observable.just("这是materialize")
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)
/*
输出结果:
这是materialize
*/

一对比就明显了,materialize发出来的是事件,而不是对应的值。
如果用了materialize还是要获取值就这样操作

Observable.just("这是materialize")
    .materialize()
    .subscribe(onNext: { (event) in
        print(event.element!)
    })
    .disposed(by: disposeBag)

还有另外一种方式 dematerialize

dematerialize

dematerializematerialize正好相反,可以理解成解码跟编码的关系。

案例

Observable.just("这是materialize")
    .materialize()
    .dematerialize()
    .subscribe(onNext: { string in
        print(string!)
    })
    .disposed(by: disposeBag)

timeout

如果源 Observable 在规定时间内没有发出任何元素,就产生一个超时的 error 事件

如果 Observable 在一段时间内没有产生元素,timeout 操作符将使它发出一个 error 事件。

案例

Observable.just("这是延时订阅")
    .delaySubscription(.seconds(3), scheduler: MainScheduler.instance) //延迟3秒才开始订阅
    .timeout(.seconds(2), scheduler: MainScheduler.instance)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

输出结果:

Unhandled error happened: Sequence timeout.
 subscription called from:

ignoreElements

忽略掉所有的next事件,只发出 error 或 completed 事件

ignoreElements 操作符将阻止 Observable 发出 next 事件,但是允许他发出 error 或 completed 事件。

如果你并不关心 Observable 的任何元素,你只想知道 Observable 在什么时候终止,那就可以使用 ignoreElements 操作符。

当我们要订阅的时候,会发现提示中并不包含onNext

那么如果我们自己强行写会怎么样呢

还是被阻止了。

startWith

将一些元素插入到序列的头部

startWith 操作符会在 Observable 头部插入一些元素。

案例

let disposeBag = DisposeBag()

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

打印结果:

3
🅰️
🅱️
2
1
🐶
🐱
🐭
🐹

buffer

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

buffer 操作符将缓存 Observable 中发出的新元素,当元素达到某个数量,或者经过了特定的时间,它就会将这个元素集合发送出来。

就是buffer会将我们发出的元素,按照一定的数量,将他们组合成数组,然后再一起发出来。

案例

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

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

打印结果:

["a", "b", "c"]
["1", "2", "3"]
["1", "2", "3"]
["1", "2", "3"]
["1", "2", "3"]
Unhandled error happened: Sequence timeout.
 subscription called from:
//如果没有设置`timeout`那么后续他将会发出,按设定的时间每次发出一个空数组。
[]
[]
[]

window

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

window操作符和 buffer十分相似,buffer周期性的将缓存的元素集合发送出来,而 window 周期性的将元素集合以 Observable 的形态发送出来。

buffer要等到元素搜集完毕后,才会发出元素序列。而 window可以实时发出元素序列。

案例

let subject = PublishSubject<String>()
subject
    .window(timeSpan: .seconds(3), count: 3, scheduler: MainScheduler.instance)
    .timeout(.seconds(2), scheduler: MainScheduler.instance)
    .subscribe(onNext: {
        print($0)
    }).disposed(by: disposeBag)

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

打印结果:

RxSwift.AddRef<Swift.String>
RxSwift.AddRef<Swift.String>
RxSwift.AddRef<Swift.String>
Unhandled error happened: Sequence timeout.
 subscription called from:

由结果看来,他确实如文档所说,打印的只是一些成组的序列。
那么我们在给这个$0加上订阅会如何呢

let subject = PublishSubject<String>()
subject
    .window(timeSpan: .seconds(3), count: 3, scheduler: MainScheduler.instance)
    .timeout(.seconds(2), scheduler: MainScheduler.instance)
    
    .subscribe(onNext: {
        $0.subscribe(onNext: { print($0) })
    }).disposed(by: disposeBag)

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

打印结果:

1
2
3
1
2
3

groupBy

将源 Observable 分解为多个子 Observable,并且每个子 Observable 将源 Observable 中“相似”的元素发送出来

groupBy 操作符将源 Observable 分解为多个子 Observable,然后将这些子 Observable 发送出来。

它会将元素通过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来。

案例

Observable<Int>.of(0, 1, 2, 3, 4, 5,3,2,1)
    .groupBy(keySelector: { (element) -> String in
        return element % 2 == 0 ? "偶数" : "基数"
    })
    .subscribe { (event) in
        print(event)
        switch event {
        case .next(let group):
            group.asObservable().subscribe({ (event) in
                print("key: \(group.key)     \(event)")
            })
        default:
            print("")
        }
    }
    .dispose()

打印结果:

key: 基数     next(1)
key: 偶数     next(2)
key: 基数     next(3)
key: 偶数     next(4)
key: 基数     next(5)
key: 基数     next(3)
key: 偶数     next(2)
key: 基数     next(1)
key: 偶数     completed
key: 基数     completed
completed

single

限制 Observable 只有一个元素,否出发出一个 error事件

single操作符将限制 Observable 只产生一个元素。如果 Observable 只有一个元素,它将镜像这个 Observable 。如果 Observable 没有元素或者元素数量大于一,它将产生一个error 事件。

如果发送的数量大于1或者 什么都没做,就发出一个错误事件

案例

Observable.of(1,2,3)
.single()
.subscribe{
    print($0)
}.disposed(by: disposeBag)

打印结果:

next(1)
error(Sequence contains more than one element.)

amb

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

当你传入多个 Observables 到 amb 操作符时,它将取其中一个 Observable:第一个产生事件的那个 Observable,可以是一个 next,error 或者 completed 事件。 amb 将忽略掉其他的 Observables。

当同时监听多个Observable 时,选择其中一个,即amb(b),就不监听另外一个。

案例

let a = BehaviorSubject(value: "🐱")
let b = BehaviorSubject(value: "🐶")

Observable.of(a,b)
.flatMap{$0}
.amb(b)
.subscribe(onNext: {
    print($0)
}).disposed(by: disposeBag)

a.onNext("🐦")
b.onNext("🐔")
a.onNext("🦆")

打印结果:

🐶
🐔

reduce

持续的将 Observable 的每一个元素应用一个函数,然后发出最终结果

reduce 操作符将对第一个元素应用一个函数。然后,将结果作为参数填入到第二个元素的应用函数中。以此类推,直到遍历完全部的元素后发出最终结果。

这种操作符在其他地方有时候被称作是accumulator,aggregate,compress,fold 或者 inject

案例

let disposeBag = DisposeBag()

Observable.of(1, 2, 3)
    .reduce(2, accumulator: *)
    .subscribe(onNext: { print($0) })
    .disposed(by: disposeBag)

打印结果:

打印结果 = 1 * 2 * 3 * 2 = 12

do

当 Observable 产生某些事件时,执行某个操作

当 Observable 的某些事件产生时,你可以使用 do 操作符来注册一些回调操作。这些回调会被单独调用,它们会和 Observable 原本的回调分离。

案例

Observable.of(1, 2, 3)
    .do(onNext: { element in
        print("do next:" ,element)
    }, onError: { error in
        print("do error:", error)
    }, onCompleted: {
        print("do completed")
    }, onSubscribe: {
        print("do subscribe")
    }, onSubscribed: {
        print("do subscribed")
    }, onDispose: {
        print("do dispose")
    })
    .subscribe { event in
        switch event {
        case .next(let element):
            print("element:", element)
        case .error(let error):
            print("error:", error)
        case .completed:
            print("completed")
        }}
    .disposed(by: disposeBag)

打印结果:

do subscribe
do subscribed
do element: 1
element: 1
do element: 2
element: 2
do element: 3
element: 3
do completed
completed
do dispose

using

创建一个可被清除的资源,它和 Observable 具有相同的寿命

通过使用 using 操作符创建 Observable 时,同时创建一个可被清除的资源,一旦 Observable 终止了,那么这个资源就会被清除掉了。

案例

//一个无限序列(每隔0.1秒创建一个序列数 )
let infiniteInterval = Observable<Int>
    
    .interval(0.1, scheduler: MainScheduler.instance)
    .do(
        onNext: { print("infinite: \($0)") },
        onSubscribe: { print("开始订阅 infinite")},
        onDispose: { print("销毁 infinite")}
    )

//一个有限序列(每隔0.5秒创建一个序列数,共创建三个 )

let limited = Observable<Int>
    .interval(0.5, scheduler: MainScheduler.instance)
    .take(2)
    .do(
        onNext: { print("limited: \($0)") },
        onSubscribe: { print("开始订阅 limited")},
        onDispose: { print("销毁 limited")}
    )
//
//使用using操作符创建序列
// 当limited 销毁时,infiniteInterval同样销毁
let o: Observable<Int> = Observable.using({ () -> AnyDisposable in
    return AnyDisposable(infiniteInterval.subscribe())
}, observableFactory: { _ in return limited})

o.subscribe().disposed(by: dis)