RxSwift操作符的使用

1,258 阅读7分钟

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)