RxSwift 操作符的使用
withLatestFrom的使用
第一个 Observable 发出一个元素时,就立即取出第二个 Observable 中最新的元素,通过一个组合函数将两个最新的元素合并后发送出去
firstSubject
.withLatestFrom(secondSubject)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
firstSubject
.withLatestFrom(secondSubject) {
(first, second) in
return first + second
}.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
使用withLatestFrom的情况下,里面的信号会马上被订阅,但是flatMap不会,如果信号是一个网络请求,那么就会出现还未点击按钮,已经发送了网络请求
range该方法通过指定起始和结束数值,创建一个以这个范围内所有值作为初始值的Observable序列
let observable = Observable.range(start: 1, count: 5)
repeatElement方法创建一个可以无限发出给定元素的 Event 的 Observable 序列(永不终止)
let observable = Observable.repeatElement(1)
generate该方法创建一个只有当提供的所有的判断条件都为 true 的时候,才会给出动作的Observable序列
let observable = Observable.generate(
initialState: 0,
condition: { $0 <= 10 },
iterate: { $0 + 2 }
)
interval这个方法创建的Observable序列每隔一段设定的时间,会发出一个索引数的元素。而且它会一直发送下去
let observable = Observable<Int>.interval(1, scheduler:MainScheduler.instance)
timer
- 创建的Observable序列在经过设定的一段时间后,产生唯一的一个元素
//5秒种后发出唯一的一个元素0
let observable = Observable<Int>.timer(5, scheduler:MainScheduler.instance)
- 创建的Observable序列在经过设定的一段时间后,每隔一段时间产生一个元素
let observable = Observable<Int>.timer(5, period: 1, scheduler:MainScheduler.instance)
deferred该个方法相当于是创建一个Observable工厂,通过传入一个block来执行延迟Observable序列创建的行为,而这个block里就是真正的实例化序列对象的地方
//用于标记是奇数、还是偶数
var isOdd = true
//使用deferred()方法延迟Observable序列的初始化,通过传入的block来实现Observable序列的初始化并且返回。
let factory: Observable<Int> = Observable.deferred {
//让每次执行这个block时候都会让奇、偶数进行交替
isOdd = !isOdd
//根据isOdd参数,决定创建并返回的是奇数Observable、还是偶数Observable
if isOdd {
returnObservable.of(1, 3, 5 ,7)
} else {
return Observable.of(2, 4, 6, 8)
}
}
//第1次订阅测试
factory.subscribe { event in
print("\(isOdd)", event)
}
//第2次订阅测试
factory.subscribe { event in
print("\(isOdd)", event)
}
buffer 方法作用是缓冲组合,第一个参数是缓冲时间,第二个参数是缓冲个数,第三个参数是线程。 该方法简单来说就是缓存 Observable 中发出的新元素,当元素达到某个数量,或者经过了特定的时间,它就会将这个元素集合发送出来
subject
.buffer(timeSpan: 1, count: 3, scheduler: MainScheduler.instance)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
window操作符和buffer十分相似。不过 buffer 是周期性的将缓存的元素集合发送出来,而 window 周期性的将元素集合以 Observable 的形态发送出来,同时buffer要等到元素搜集完毕后,才会发出元素序列。而window可以实时发出元素序列
subject
.window(timeSpan: 1, count: 3, scheduler: MainScheduler.instance)
.subscribe(onNext:{ [weak self] in
print("subscribe: \($0)")
$0.asObservable()
.subscribe(onNext:{ print($0) })
.disposed(by:self!.disposeBag)
}).disposed(by: disposeBag)
concat会把多个Observable序列合并(串联)为一个Observable序列。 并且只有当前面一个Observable序列发出了completed事件,才会开始发送下一个Observable序列事件,也可以看成第一个Observable结束后,才开始订阅第二个Observable
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let subject3 = BehaviorSubject(value: "G")
// 也可以下面这种方式进行信号的连接
// subject1.concat(subject2).concat(subject3).asObservable()
Observable.of(subject1, subject2, subject3)
.concat()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
subject2.onNext("2")
subject2.onNext("3")
subject1.onNext("C")
subject3.onNext("H")
subject1.onCompleted()
subject2.onNext("3")
subject2.onCompleted()
subject3.onNext("J")
// 结果 A B C 3
concatMap与flatMap的唯一区别是:当前一个Observable元素发送完毕后,后一个Observable才可以开始发出元素。或者说等待前一个Observable产生完成事件后,才对后一个Observable进行订阅
scan就是先给一个初始化的数,然后不断的拿前一个结果和最新的值进行处理操作
Observable.of(1, 2, 3, 4, 5)
.scan(0) { acum, elem in
acum + elem
}.subscribe(onNext: {print($0) })
.disposed(by: disposeBag)
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: disposeBag)
default: print("")
}
}.disposed(by: disposeBag)
single限制只发送一次事件,或者满足条件的第一个事件
Observable.of(1, 2, 3, 4)
.single{ $0 == 2 }
.subscribe(onNext: {print($0) })
.disposed(by: disposeBag)
// 2
Observable.of("A","B","C","D")
.single()
.subscribe(onNext: {print($0) })
.disposed(by: disposeBag)
// A
elementAt该方法实现只处理在指定位置的事件
Observable.of(1, 2, 3, 4)
.elementAt(2)
.subscribe(onNext: {print($0) })
.disposed(by: disposeBag)
ignoreElements该操作符可以忽略掉所有的元素,只发出 error 或 completed 事件。如果我们并不关心 Observable 的任何元素,只想知道 Observable 在什么时候终止,那就可以使用ignoreElements操作符
Observable.of(1, 2, 3, 4)
.ignoreElements()
.subscribe{
print($0)
}.disposed(by: disposeBag)
take该方法实现仅发送Observable序列中的前n个事件,在满足数量之后会自动.completed
takeLast该方法实现仅发送 Observable 序列中的后 n 个事件
skip该方法用于跳过源Observable序列发出的前n个事件
sample除了订阅源Observable外,还可以监视另外一个Observable,即 notifier。每当收到 notifier 事件,就会从源序列取一个最新的事件并发送。而如果两次notifier事件之间没有源序列的事件,则不发送值
let source = PublishSubject<Int>()
let notifier = PublishSubject<String>()
source
.sample(notifier)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
source.onNext(1)
//让源序列接收接收消息
notifier.onNext("A")
// 1
source.onNext(2)
//让源序列接收接收消息
notifier.onNext("B")
// 2
notifier.onNext("C")
source.onNext(3)
source.onNext(4)
//让源序列接收接收消息
notifier.onNext("D")
// 4
source.onNext(5)
//让源序列接收接收消息
notifier.onCompleted()
// 5
debounce 操作符可以用来过滤掉高频产生的元素,它只会发出这种元素:该元素产生后,一段时间内没有新元素产生。换句话说就是,队列中的元素如果和下一个元素的间隔小于了指定的时间间隔,那么这个元素将被过滤掉。debounce常用在用户输入的时候,不需要每个字母敲进去都发送一个事件,而是稍等一下取最后一个事件
let times = [
["value": 1, "time": 0.1],
["value": 2, "time": 1.1],
["value": 3, "time": 1.2],
["value": 4, "time": 1.2],
["value": 5, "time": 1.4],
["value": 6, "time": 2.1]
]
//生成对应的*Observable*序列并订阅
Observable.from(times)
.flatMap { item in
return Observable.of(Int(item["value"]!))
.delaySubscription(Double(item["time"]!),
scheduler: MainScheduler.instance)
}
.debounce(0.5, scheduler: MainScheduler.instance) //只发出与下一个间隔超过*0.5*秒的元素
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
amb当传入多个Observables到 amb 操作符时,它将取第一个发出元素或产生事件的Observable,然后只发出它的元素。并忽略掉其他的 Observables
subject1
.amb(subject2)
.amb(subject3)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
takeWhile该方法依次判断 Observable 序列的每一个值是否满足给定的条件。 当第一个不满足条件的值出现时,它便自动完成
Observable.of(2, 3, 4, 5, 6)
.takeWhile { $0 < 4 }
.subscribe(onNext: {print($0) })
.disposed(by: disposeBag)
takeUntil除了订阅源Observable外,通过takeUntil方法我们还可以监视另外一个 Observable, 即notifier。 如果notifier发出值或 complete通知,那么源Observable便自动完成,停止发送事件
skipWhile该方法用于跳过前面所有满足条件的事件。 一旦遇到不满足条件的事件,之后就不会再跳过了
Observable.of(2, 3, 4, 5, 6, 2)
.skipWhile { $0 < 4 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
// 4 5 6 2
skipUntil同上面的takeUntil一样,skipUntil 除了订阅源Observable 外,通过skipUntil方法我们还可以监视另外一个Observable, 即 notifier 。与takeUntil相反的是。源Observable序列事件默认会一直跳过,直到 notifier 发出值或 complete 通知
startWith 该方法会在Observable序列开始之前插入一些事件元素。即发出事件消息之前,会先发出这些预先插入的事件消息
Observable.of("2","3")
.startWith("a")
.startWith("b")
.startWith("c")
.subscribe(onNext: {print($0) })
.disposed(by: disposeBag)
// c b a 2 3
switchLatest 有点像其他语言的switch方法,可以对事件流进行转换。 比如本来监听的subject1,我可以通过更改variable里面的value更换事件源。变成监听subject2
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.switchLatest()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
subject1.onNext("C")
//改变事件源
variable.value = subject2
subject1.onNext("D")
subject2.onNext("2")
//改变事件源
variable.value = subject1
subject2.onNext("3")
subject1.onNext("E")
switchLatest有点像其他语言的switch方法,可以对事件流进行转换。 比如本来监听的subject1,我可以通过更改variable里面的value更换事件源。变成监听subject2
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.switchLatest()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("B")
subject1.onNext("C")
//改变事件源
variable.value = subject2
subject1.onNext("D")
subject2.onNext("2")
//改变事件源
variable.value = subject1
subject2.onNext("3")
subject1.onNext("E")
toArray该操作符先把一个序列转成一个数组,并作为一个单一的事件发送,然后结束
Observable.of(1, 2, 3)
.toArray()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
reduce接受一个初始值,和一个操作符号。reduce 将给定的初始值,与序列里的每个值进行累计运算。得到一个最终结果,并将其作为单个值发送出去
Observable.of(1, 2, 3, 4, 5)
.reduce(0, accumulator: +)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
publish方法会将一个正常的序列转换成一个可连接的序列。同时该序列不会立刻发送事件,只有在调用 connect 之后才会开始,并且连接后多个监听者接受到的数据都是一样的,及时后面那个监听者延迟了5秒,开始监听后也是从5开始接受数据
//每隔1秒钟发送1个事件
let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.publish()
//第一个订阅者(立刻开始订阅)
_ = interval
.subscribe(onNext: { print("订阅1: \($0)") })
//相当于把事件消息推迟了两秒
delay(2) {
_ = interval.connect()
}
//第二个订阅者(延迟5秒开始订阅)
delay(5) {
_ = interval
.subscribe(onNext: { print("订阅2: \($0)") })
}
replay 同上面的publish方法相同之处在于:会将一个正常的序列转换成一个可连接的序列。同时该序列不会立刻发送事件,只有在调用 connect 之后才会开始。 replay 与 publish 不同在于:新的订阅者还能接收到订阅之前的事件消息(数量由设置的 bufferSize 决定)
multicast方法同样是将一个正常的序列转换成一个可连接的序列。 同时 multicast 方法还可以传入一个 Subject,每当序列发送事件时都会触发这个 Subject 的发送
//创建一个Subject(后面的multicast()方法中传入)
let subject = PublishSubject<Int>()
//这个Subject的订阅
_ = subject
.subscribe(onNext: { print("Subject: \($0)") })
//每隔1秒钟发送1个事件
let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.multicast(subject)
//第一个订阅者(立刻开始订阅)
_ = interval
.subscribe(onNext: { print("订阅1: \($0)") })
//相当于把事件消息推迟了两秒
delay(2) {
_ = interval.connect()
}
//第二个订阅者(延迟5秒开始订阅)
delay(5) {
_ = interval
.subscribe(onNext: { print("订阅2: \($0)") })
}
delay该操作符会将 Observable 的所有元素都先拖延一段设定好的时间,然后才将它们发送出来
delaySubscription使用该操作符可以进行延时订阅。即经过所设定的时间后,才对 Observable 进行订阅操作
materialize该操作符可以将序列产生的事件,转换成元素。 通常一个有限的 Observable 将产生零个或者多个 onNext 事件,最后产生一个 onCompleted 或者 onError 事件。而 materialize 操作符会将 Observable 产生的这些事件全部转换成元素,然后发送出来
dematerialize该操作符的作用和 materialize 正好相反,它可以将 materialize 转换后的元素还原
timeout使用该操作符可以设置一个超时时间。如果源 Observable 在规定时间内没有发任何出元素,就产生一个超时的 error 事件
//定义好每个事件里的值以及发送的时间
let times = [
["value": 1, "time": 0],
["value": 2, "time": 0.5],
["value": 3, "time": 1.5],
["value": 4, "time": 4],
["value": 5, "time": 5]]
//生成对应的*Observable*序列并订阅
Observable.from(times)
.flatMap { item in
return Observable.of(Int(item["value"]!))
.delaySubscription(Double(item["time"]!),
scheduler: MainScheduler.instance)
}.timeout(2, scheduler: MainScheduler.instance) //超过两秒没发出元素,则产生error事件
.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}).disposed(by: disposeBag)