RxSwift系列(二)操作符
一、变换操作符:buffer、map、compactMap等
1.buffer
buffer方法作用是缓冲组合,第一个参数是缓冲时间,第二个参数是缓冲个数,第三个参数是线程。缓存 Observable 中发出的新元素,当元素达到某个数量,或者经过了特定的时间,它就会将这个元素集合发送出来。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {let subject = PublishSubject<String>()//每缓存3个元素则组合起来一起发出。//如果1秒钟内不够3个也会发出(有几个发几个,一个都没有发空数组 [])subject.buffer(timeSpan: 1, count: 3, scheduler: MainScheduler.instance).subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject.onNext("a")subject.onNext("b")subject.onNext("c")subject.onNext("1")subject.onNext("2")subject.onNext("3")}
}
2.window
● window 操作符和 buffer 十分相似。不过 buffer 是周期性的将缓存的元素集合发送出来,而 window 周期性的将元素集合以 Observable 的形态发送出来。
● 同时 buffer要等到元素搜集完毕后,才会发出元素序列。而 window 可以实时发出元素序列。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {let subject = PublishSubject<String>()//每3个元素作为一个子Observable发出。subject.window(timeSpan: 1, count: 3, scheduler: MainScheduler.instance).subscribe(onNext: { [weak self] inprint("subscribe: \($0)")$0.asObservable().subscribe(onNext: { print($0) }).disposed(by: self!.disposeBag)}).disposed(by: disposeBag)subject.onNext("a")subject.onNext("b")subject.onNext("c")subject.onNext("1")subject.onNext("2")subject.onNext("3")}
}
3.map
通过传入一个函数闭包把原来的 Observable 序列转变为一个新的 Observable 序列。
let disposeBag = DisposeBag()Observable.of(1, 2, 3).map { $0 * 10}.subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果
//10
//20
//30
4.flatMap
flatMap 操作符会对源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。 然后将这些 Observables 的元素合并之后再发送出来。即又将其 “拍扁”(降维)成一个 Observable 序列。这个操作符是非常有用的。比如当 Observable 的元素本生拥有其他的 Observable 时,我们可以将所有子 Observables 的元素发送出来。
let disposeBag = DisposeBag()let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")let variable = Variable(subject1)variable.asObservable().flatMap { $0 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject1.onNext("B")
variable.value = subject2
subject2.onNext("2")
subject1.onNext("C")//运行结果
//A
//B
//1
//2
//C
注意:flatMap并不保证事件的顺序,需要保证顺序则需要使用 concatMap
5.concatMap
concatMap 与 flatMap 的唯一区别是:当前一个 Observable 元素发送完毕后,后一个Observable 才可以开始发出元素。
6.scan
先给一个初始化的数,然后不断的拿前一个结果和最新的值进行处理操作。
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4, 5).scan(0) { acum, elem inacum + elem}.subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果:1 3 6 10 15
7.groupBy
将源 Observable 分解为多个子 Observable,然后将这些子 Observable 发送出来。该操作符会将元素通过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来。
let disposeBag = DisposeBag()//将奇数偶数分成两组
Observable<Int>.of(0, 1, 2, 3, 4, 5).groupBy(keySelector: { (element) -> String inreturn element % 2 == 0 ? "偶数" : "基数"}).subscribe { (event) inswitch event {case .next(let group):group.asObservable().subscribe({ (event) inprint("key:\(group.key) event:\(event)")}).disposed(by: disposeBag)default:print("")}}
.disposed(by: disposeBag)
二、过滤操作符:filter、take、skip等
1.filter
用来过滤掉某些不符合要求的事件
let disposeBag = DisposeBag()Observable.of(2, 30, 22, 5, 60, 3, 40 ,9).filter {$0 > 10}.subscribe(onNext: { print($0) }).disposed(by: disposeBag)//运行结果: 30 22,60,40
2.distinctUntilChanged
过滤掉连续重复的事件
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 1, 1, 4).distinctUntilChanged().subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果:1 2 3 1 4
3.single
● 限制只发送一次事件,或者满足条件的第一个事件。
● 如果存在有多个事件或者没有事件都会发出一个 error 事件。
● 如果只有一个事件,则不会发出 error事件
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4).single{ $0 == 2 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果: 2Observable.of("A", "B", "C", "D").single().subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果
//A
//Unhandled error happened:Sequence contains more than one element.
4.elementAt
只处理在指定位置的事件.
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4).elementAt(2).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果: 3
5.ignoreElements
可以忽略掉所有的元素,只发出 error或completed 事件。如果我们并不关心 Observable 的任何元素,只想知道 Observable 在什么时候终止,那就可以使用 ignoreElements 操作符。
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4).ignoreElements().subscribe{print($0)}.disposed(by: disposeBag)
6.take
该方法实现仅发送 Observable 序列中的前 n 个事件,在满足数量之后会自动 .completed。
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4).take(2).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果: 1 2
7.takeLast
仅发送 Observable序列中的后 n 个事件。
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4).takeLast(1).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果: 4
8.skip
跳过源 Observable 序列发出的前 n 个事件。
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4).skip(2).subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果:3 4
9.sample
● Sample 除了订阅源Observable 外,还可以监视另外一个 Observable, 即 notifier 。
● 每当收到 notifier 事件,就会从源序列取一个最新的事件并发送。而如果两次 notifier 事件之间没有源序列的事件,则不发送值。
let disposeBag = DisposeBag()let source = PublishSubject<Int>()
let notifier = PublishSubject<String>()source.sample(notifier).subscribe(onNext: { print($0) }).disposed(by: disposeBag)source.onNext(1)//让源序列接收接收消息
notifier.onNext("A")source.onNext(2)//让源序列接收接收消息
notifier.onNext("B")
notifier.onNext("C")source.onNext(3)
source.onNext(4)//让源序列接收接收消息
notifier.onNext("D")source.onNext(5)//让源序列接收接收消息
notifier.onCompleted()//运行结果: 1 2 4 5
10.debounce
● 可以用来过滤掉高频产生的元素,它只会发出这种元素:该元素产生后,一段时间内没有新元素产生。换句话说,队列中的元素如果和下一个元素的间隔小于了指定的时间间隔,那么这个元素将被过滤掉。
● debounce 常用在用户输入的时候,不需要每个字母敲进去都发送一个事件,而是稍等一下取最后一个事件
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {//定义好每个事件里的值以及发送的时间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 inreturn 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)}
}//运行结果:1 5 6
三、条件和布尔操作符:amb、takeWhile、skipWhile等
1.amb
当传入多个 Observables 到 amb 操作符时,取第一个发出元素或产生事件的 Observable,然后只发出它的元素。并忽略掉其他的 Observables。
let disposeBag = DisposeBag()let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()
let subject3 = PublishSubject<Int>()subject1.amb(subject2)//只取第一个amb的Observable的事件.amb(subject3).subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject2.onNext(1)
subject1.onNext(20)
subject2.onNext(2)
subject1.onNext(40)
subject3.onNext(0)
subject2.onNext(3)
subject1.onNext(60)
subject3.onNext(0)
subject3.onNext(0)//运行结果:1 2 3
2.takeWhile
依次判断 Observable 序列的每一个值是否满足给定的条件。 当第一个不满足条件的值出现时,它便自动完成。
let disposeBag = DisposeBag()Observable.of(2, 3, 4, 5, 6).takeWhile { $0 < 4 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果:2 3
3.takeUntil
● 除了订阅源 Observable 外,通过 takeUntil 方法我们还可以监视另外一个 Observable, 即 notifier。
● 如果 notifier 发出值或 complete 通知,那么源 Observable 便自动完成,停止发送事件
let disposeBag = DisposeBag()let source = PublishSubject<String>()
let notifier = PublishSubject<String>()source.takeUntil(notifier).subscribe(onNext: { print($0) }).disposed(by: disposeBag)source.onNext("a")
source.onNext("b")
source.onNext("c")
source.onNext("d")//停止接收消息
notifier.onNext("z")source.onNext("e")
source.onNext("f")
source.onNext("g")//运行结果:a b c d
4.skipWhile
● 用于跳过前面所有满足条件的事件。
● 一旦遇到不满足条件的事件,之后就不会再跳过了
let disposeBag = DisposeBag()Observable.of(2, 3, 4, 5, 6).skipWhile { $0 < 4 }.subscribe(onNext: { print($0) }).disposed(by: disposeBag)}
}
//运行结果:4 5 6
5.skipUntil
skipUntil 除了订阅源 Observable 外,还可以监视另外一个 Observable, 即 notifier。与 takeUntil 相反的是:源 Observable 序列事件默认会一直跳过,直到 notifier 发出值或 complete 通知。
let disposeBag = DisposeBag()let source = PublishSubject<Int>()
let notifier = PublishSubject<Int>()source.skipUntil(notifier).subscribe(onNext: { print($0) }).disposed(by: disposeBag)source.onNext(1)
source.onNext(2)
source.onNext(3)
source.onNext(4)
source.onNext(5)//开始接收消息
notifier.onNext(0)source.onNext(6)
source.onNext(7)
source.onNext(8)//仍然接收消息
notifier.onNext(0)source.onNext(9)//运行结果:6 7 8 9
四、结合操作符:startWith、merge、zip等
1.startWith
该方法会在 Observable 序列开始之前插入一些事件元素。即发出事件消息之前,会先发出这些预先插入的事件消息。
let disposeBag = DisposeBag()Observable.of("2", "3").startWith("a").startWith("b").startWith("c").subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果:c b a 2 3
2.merge
该方法可以将多个(两个或两个以上的)Observable 序列合并成一个 Observable序列。
let disposeBag = DisposeBag()let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<Int>()Observable.of(subject1, subject2).merge().subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject1.onNext(20)
subject1.onNext(40)
subject1.onNext(60)
subject2.onNext(1)
subject1.onNext(80)
subject1.onNext(100)
subject2.onNext(1)//运行结果:20 40 60 1 80 100 1
3.zip
该方法可以将多个(两个或两个以上的)Observable 序列压缩成一个 Observable 序列。而且它会等到每个 Observable 事件一一对应地凑齐之后再合并。
let disposeBag = DisposeBag()let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()Observable.zip(subject1, subject2) {"\($0)\($1)"}.subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)//运行结果: 1A 2B 3C 4D
4.combineLatest
该方法同样是将多个(两个或两个以上的)Observable 序列元素进行合并。但与 zip 不同的是,每当任意一个 Observable 有新的事件发出时,它会将每个 Observable 序列的最新的一个事件元素进行合并。
let disposeBag = DisposeBag()let subject1 = PublishSubject<Int>()
let subject2 = PublishSubject<String>()Observable.combineLatest(subject1, subject2) {"\($0)\($1)"}.subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject1.onNext(1)
subject2.onNext("A")
subject1.onNext(2)
subject2.onNext("B")
subject2.onNext("C")
subject2.onNext("D")
subject1.onNext(3)
subject1.onNext(4)
subject1.onNext(5)//运行结果:1A 2A 2B 2C 2D 3D 4D 5D
5.withLatestFrom
该方法将两个 Observable 序列合并为一个。每当 self 队列发射一个元素时,便从第二个序列中取出最新的一个值。
let disposeBag = DisposeBag()let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()subject1.withLatestFrom(subject2).subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject1.onNext("A")
subject2.onNext("1")
subject1.onNext("B")
subject1.onNext("C")
subject2.onNext("2")
subject1.onNext("D")//运行结果:1 1 2
6.switchLatest
有点像其他语言的switch 方法,可以对事件流进行转换。比如本来监听的 subject1,我可以通过更改 variable 里面的 value 更换事件源。变成监听 subject2。
let disposeBag = DisposeBag()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")//运行结果:A B C 1 2 D E
五、算术&聚合操作符:toArray、reduce、concat等
1.toArray
该操作符先把一个序列转成一个数组,并作为一个单一的事件发送,然后结束
let disposeBag = DisposeBag()Observable.of(1, 2, 3).toArray().subscribe(onNext: { print($0) }).disposed(by: disposeBag)
//运行结果:[1, 2, 3]
2.reduce
● reduce 接受一个初始值,和一个操作符号。
● reduce 将给定的初始值,与序列里的每个值进行累计运算。得到一个最终结果,并将其作为单个值发送出去
let disposeBag = DisposeBag()Observable.of(1, 2, 3, 4, 5).reduce(0, accumulator: +).subscribe(onNext: { print($0) }).disposed(by: disposeBag)//运行结果: 15
3.concat
● concat 会把多个 Observable 序列合并(串联)为一个 Observable 序列。
● 并且只有当前面一个 Observable 序列发出了 completed 事件,才会开始发送下一个 Observable 序列事件。
let disposeBag = DisposeBag()let subject1 = BehaviorSubject(value: 1)
let subject2 = BehaviorSubject(value: 2)let variable = Variable(subject1)
variable.asObservable().concat().subscribe(onNext: { print($0) }).disposed(by: disposeBag)subject2.onNext(2)
subject1.onNext(1)
subject1.onNext(1)
subject1.onCompleted()variable.value = subject2
subject2.onNext(2)//运行结果:1 1 1 2 2
六、连接操作符:connect、publish、replay等
可连接的序列(Connectable Observable):
(1)可连接的序列和一般序列不同在于:有订阅时不会立刻开始发送事件消息,只有当调用 connect()之后才会开始发送值。
(2)可连接的序列可以让所有的订阅者订阅后,才开始发出事件消息,从而保证我们想要的所有订阅者都能接收到事件消息。
1.publish
publish 方法会将一个正常的序列转换成一个可连接的序列。同时该序列不会立刻发送事件,只有在调用 connect 之后才会开始。
///定义延迟执行方法
/// - Parameters:
/// - delay: 延迟时间(秒)
/// - closure: 延迟执行的闭包
public func delay(_ delay: Double, closure: @escaping () -> Void) {DispatchQueue.main.asyncAfter(deadline: .now() + delay) {closure()}
}//每隔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)") })
}//运行结果
//订阅1: 0
//订阅1: 1
//订阅1: 2
//订阅2: 2
//订阅1: 3
//订阅2: 3
//订阅1: 4
//订阅2: 4
2.replay
● 与publish相同之处在于:会将将一个正常的序列转换成一个可连接的序列。同时该序列不会立刻发送事件,只有在调用 connect 之后才会开始。
● 与publish不同在于:新的订阅者还能接收到订阅之前的事件消息(数量由设置的 bufferSize 决定)。
//每隔1秒钟发送1个事件
let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance).replay(5)//第一个订阅者(立刻开始订阅)
_ = interval.subscribe(onNext: { print("订阅1: \($0)") })//相当于把事件消息推迟了两秒
delay(2) {_ = interval.connect()
}//第二个订阅者(延迟5秒开始订阅)
delay(5) {_ = interval.subscribe(onNext: { print("订阅2: \($0)") })
}//运行结果
//订阅1: 0
//订阅1: 1
//订阅2: 0
//订阅2: 1
//订阅1: 2
//订阅2: 2
//订阅1: 3
//订阅2: 3
//订阅1: 4
3.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)") })
}//运行结果:
//Subject: 0
//订阅1: 0
//Subject: 1
//订阅1: 1
//Subjec: 2
//订阅1: 2
//订阅2: 2
//Subject: 3
//订阅1: 3
//订阅2: 3
4.refCount
● 将可被连接的 Observable 转换为普通 Observable
● 即该操作符可以自动连接和断开可连接的 Observable。当第一个观察者对可连接的Observable 订阅时,那么底层的 Observable 将被自动连接。当最后一个观察者离开时,那么底层的 Observable 将被自动断开连接。
//每隔1秒钟发送1个事件
let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance).publish().refCount()//第一个订阅者(立刻开始订阅)
_ = interval.subscribe(onNext: { print("订阅1: \($0)") })//第二个订阅者(延迟5秒开始订阅)
delay(5) {_ = interval.subscribe(onNext: { print("订阅2: \($0)") })
}//运行结果
//订阅1: 0
//订阅1: 1
//订阅1: 2
//订阅1: 3
//订阅1: 4
//订阅1: 5
//订阅2: 5
//订阅1: 6
//订阅2: 6
//订阅1: 7
//订阅2:7
5.share(relay:)
● 该操作符将使得观察者共享源 Observable,并且缓存最新的 n 个元素,将这些元素直接发送给新的观察者。
● 简单来说 shareReplay 就是 replay 和 refCount 的组合。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {override func viewDidLoad() {//每隔1秒钟发送1个事件let interval = Observable<Int>.interval(1, scheduler: MainScheduler.instance).share(replay: 5)//第一个订阅者(立刻开始订阅)_ = interval.subscribe(onNext: { print("订阅1: \($0)") })//第二个订阅者(延迟5秒开始订阅)delay(5) {_ = interval.subscribe(onNext: { print("订阅2: \($0)") })}}
}//运行结果
//订阅1: 0
//订阅1: 1
//订阅1: 2
//订阅1: 3
//订阅1: 4
//订阅2: 0
//订阅2: 1
//订阅2: 2
//订阅2: 3
//订阅2: 4
//订阅1: 5
//订阅2: 5
//订阅1: 6
//订阅2: 6
七、其他操作符:delay、materialize、timeout等
1.delay
将 Observable 的所有元素都先拖延一段设定好的时间,然后才将它们发送出来。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {Observable.of(1, 2, 1).delay(3, scheduler: MainScheduler.instance) //元素延迟3秒才发出.subscribe(onNext: { print($0) }).disposed(by: disposeBag)}
}
2.delaySubscription
延时订阅。即经过所设定的时间后,才对 Observable 进行订阅操作。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {Observable.of(1, 2, 1).delaySubscription(3, scheduler: MainScheduler.instance) //延迟3秒才开始订阅.subscribe(onNext: { print($0) }).disposed(by: disposeBag)}
}
3.materialize
● 该操作符可以将序列产生的事件,转换成元素。
● 通常一个有限的 Observable 将产生零个或者多个 onNext 事件,最后产生一个 onCompleted 或者onError事件。而 materialize 操作符会将 Observable 产生的这些事件全部转换成元素,然后发送出来。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {Observable.of(1, 2, 1).materialize().subscribe(onNext: { print($0) }).disposed(by: disposeBag)}
}//运行结果
//next(1)
//next(2)
//next(1)
//completed
4.dematerialize
该操作符的作用和 materialize 正好相反,它可以将 materialize 转换后的元素还原。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {Observable.of(1, 2, 1).materialize().dematerialize().subscribe(onNext: { print($0) }).disposed(by: disposeBag)}
}
5.timeout
设置一个超时时间。如果源 Observable 在规定时间内没有发任何出元素,就产生一个超时的 error 事件。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {let disposeBag = DisposeBag()override func viewDidLoad() {//定义好每个事件里的值以及发送的时间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 inreturn Observable.of(Int(item["value"]!)).delaySubscription(Double(item["time"]!),scheduler: MainScheduler.instance)}.timeout(2, scheduler: MainScheduler.instance) //超过两秒没发出元素,则产生error事件.subscribe(onNext: { element inprint(element)}, onError: { error inprint(error)}).disposed(by: disposeBag)}
}//运行结果
//1
//2
//3
//Sequence timeout
6.using
使用 using 操作符创建 Observable 时,同时会创建一个可被清除的资源,一旦 Observable终止了,那么这个资源就会被清除掉了。
import UIKit
import RxSwift
import RxCocoaclass ViewController: UIViewController {override func viewDidLoad() {//一个无限序列(每隔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操作符创建序列let o: Observable<Int> = Observable.using({ () -> AnyDisposable inreturn AnyDisposable(infiniteInterval$.subscribe())}, observableFactory: { _ in return limited$ })o.subscribe()}
}class AnyDisposable: Disposable {let _dispose: () -> Voidinit(_ disposable: Disposable) {_dispose = disposable.dispose}func dispose() {_dispose()}
}//运行结果
//开始订阅 infinite$
//开始订阅 limited$
//infinited$: 0
//infinited$: 1
//infinited$: 2
//infinited$: 3
//infinited$: 4
//limited$: 0
//infinited$: 5
//infinited$: 6
//infinited$: 7
//infinited$: 8
//infinited$: 9
//limited$: 1
//销毁 limited$
//销毁 infinited$
相关文章:
RxSwift系列(二)操作符
一、变换操作符:buffer、map、compactMap等 1.buffer buffer方法作用是缓冲组合,第一个参数是缓冲时间,第二个参数是缓冲个数,第三个参数是线程。缓存 Observable 中发出的新元素,当元素达到某个数量,或者…...
Gin框架简易搭建(3)--Grom与数据库
写在前面 项目地址 个人认为GORM 指南这个网站是相比较之下最为清晰的框架介绍 但是它在环境搭建阶段对于初学者而言不是很友好,尤其是使用mysql指令稍有不同,以及更新的方法和依赖问题都是很让人头疼的,而且这些报错并非逻辑上的…...
JavaScript模块化-CommonJS规范和ESM规范
1 ES6模块化 1.1 ES6基本介绍 ES6 模块是 ECMAScript 2015(ES6)引入的标准模块系统,广泛应用于浏览器环境下的前端开发。Node.js环境主要使用CommonJS规范。ESM使用import和export来实现模块化开发从而解决了以下问题: 全局作用…...
解决银河麒麟V10中的apt Lock异常
解决银河麒麟V10中的apt Lock异常 一、查找并杀掉apt进程二、删除锁文件三、重新尝试apt命令 💖The Begin💖点点关注,收藏不迷路💖 在使用银河麒麟V10的apt命令时,如果遇到lock异常,可以按以下步骤解决&…...
windows11环境安装lua及luarocks(踩坑篇)
一、lua安装及下载 官方地址: Lua Binaries Download 从这里就有坑了,下载后先解压win64_bin.zip,之后解压lib,用lib中的文件替换win64的,并把include文件夹复制过去,之后复制并重命名lua54,方…...
Glide基本用法及With方法源码解析
文章目录 引入优点 使用步骤导入依赖权限使用 其他用法占位符错误图片后备回调符圆角过渡动画大小调整gif缩略图 使用RequestOptions缓存机制设置缓存策略清理缓存 使用集成库OkHttpVolley with源码解析getRetrieverGlide.getinitializeGlide getRequestManagerRetriever Reque…...
html中的文本标签(含标签的实现案例)
目录 1.标题标签 2.标题标签的align属性 3.段落标签 4.水平线标签hr 5.换行标签br 6.文本样式标签font 编辑7.文本格式化标签 8.文本语义标签 1)时间time标签 2)文本高亮Mark标签 3)cite标签 9.特殊字符标签 10.图像标签img 附录ÿ…...
通信协议感悟
本文结合个人所学,简要讲述SPI,I2C,UART通信的特点,限制。 1.同步通信 UART,SPI,I2C三种串行通讯方式,SPI功能引脚为CS,CLK,MOSI,MISO;I2C功能引…...
IDEA几大常用AI插件
文章目录 前言列表GPT中文版TalkXBito AIIDEA自带的AI 前言 最近AI、GPT特别火,IDEA里面又有一堆插件支持GPT,所以做个专题比较一下各个GPT插件 列表 先看idea的plugins里支持哪些,搜索“GPT”之后得到的,我用下来感觉第一第二和…...
51单片机学习第六课---B站UP主江协科技
DS18B20 1、基本知识讲解 2、DS18B20读取温度值 main.c #include<regx52.h> #include"delay.h" #include"LCD1602.h" #include"key.h" #include"DS18B20.h"float T; void main () {LCD_Init();LCD_ShowString(1,1,"temp…...
sadTalker本地编译
SadTalker一款开源的可生成逼真的人像动画的工具。它利用深度学习技术,根据输入的图像和音频,生成具有生动表情和动作的视频。用户可以通过上传照片或使用预设的模型,轻松创建个性化的动画内容. 以上是官网的图, 下边是本地部署生成的,效果差…...
强化学习核心概念与公式总结
强化学习核心概念与公式总结 1. 核心概念 1.1 智能体(Agent)和环境(Environment) 智能体:学习和做决策的实体环境:智能体交互的外部系统1.2 状态(State) 描述环境在特定时刻的情况1.3 动作(Action) 智能体可以执行的操作1.4 奖励(Reward) 环境对智能体动作的即时反馈1.5 策…...
基础算法--双指针【概念+图解+题解+解释】
更多精彩内容..... 🎉❤️播主の主页✨😘 Stark、-CSDN博客 本文所在专栏: 数据结构与算法_Stark、的博客-CSDN博客 其它专栏: 学习专栏C语言_Stark、的博客-CSDN博客 项目实战C系列_Stark、的博客-CSDN博客 座右铭&a…...
国产化系统/鸿蒙开发足浴店收银源码-收缩左侧———未来之窗行业应用跨平台架构
一、左侧展开后 二、代码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head><title></title><meta http-equiv"Content-Type" content"text/html; charsetUTF-8"><style t…...
如何从硬盘恢复丢失/删除的视频
您是否想知道是否可以恢复已删除的视频? 幸运的是,您可以使用奇客数据恢复从硬盘驱动器、SD 卡和 USB 闪存驱动器恢复已删除的视频文件。 你有没有遇到过这样的情况:当你随机删除文件以释放空间时,你不小心按下了一些重要视频的…...
《Effective C++》第三版——设计与声明(1)
参考资料: 《Effective C》第三版 注意:《Effective C》不涉及任何 C11 的内容,因此其中的部分准则可能在 C11 出现后有更好的实现方式。 条款 18:让接口容易被正确使用,不易被误用 好的接口很容易被正确使用&…...
数值计算的程序设计问题举例
### 数值计算的程序设计问题 #### 1. 结构静力分析计算 **涉及领域**:工程力学、建筑工程 **主要问题**:线性代数方程组(Linear Algebraic Equations) **解释说明**: 在结构静力分析中,我们需要解决复杂的…...
Java之方法的使用
修饰符 返回值 方法名称(形式参数){ } 当无参数的时候形式参数中什么都不写。 列如求两个数相加 修饰符可有可无。 方法重载: 1.方法名相同 2.参数列表不同 3。返回值不影响重载...
sudo 命令:掌握系统权限控制,实现安全高效管理
一、命令简介 sudo 命令允许系统管理员授权普通用户执行特定命令,并以管理员身份运行这些命令,通常需要输入用户自己的密码。 sudo 全称是"substitute user do",意为“替用户做”,也就是“以另一个用户的身…...
AndroidStudio导入so文件
点击app 右键依次选择New-Floder-JNI Floder 创建jni目录 将需要的so文件拷贝到jni目录 在app目录下,build.gradle文件的android{}中添加: sourceSets {main{jniLibs.srcDirs [src/main/jni]}}点击一下Sync Project with Gradle Files 然后编译生成AP…...
Kuebernetes 群集基于 Docker 部署
Kuebernetes 群集基于 Docker 部署 实验报告资源列表基础环境一、准备 Docker1、安装 Docker 二、安装 Kubeadm 工具1、配置 yum 源2、安装 Kubeadm 工具 三、初始化 Master 节点1、配置 Master 节点2、常见故障 四、Node 节点加入集群五、部署网络插件(CNI…...
追随 HarmonyOS NEXT,Solon v3.0 将在10月8日发布
Solon (开放原子开源基金会,孵化项目)原计划10月1日发布 v3.0 正式版。看到 HarmonyOS NEXT 将在 10月8日启用公测,现改为10月8日发布以示庆贺。另外,Solon 将在2025年启动“仓颉”版开发(届时,…...
服装时尚与动漫游戏的跨界联动:创新运营与策划策略研究
摘要:本论文聚焦于服装时尚与动漫游戏的跨界联动现象,深入探讨其在运营和策划方向的策略与实践。通过对相关理论的梳理和实际案例的分析,阐述了跨界联动的背景、意义、模式以及面临的挑战。研究发现,成功的跨界联动能够实现品牌价…...
Redis中String类型的常用命令(append,getrenge,setrange等命令)
Redis----String命令 前言.常见的String存储类型. 常见命令1. set 命令2. get 命令3. mget命令与mset命令4. setnx命令5. setex与psetex命令6. incr与incrby与incrbyfloat命令7. decr与decrby命令8. append命令9. getrange和setrange命令10. strlen命令. 前言. 常见的String存…...
深度拆解:如何在Facebook上做跨境电商?
国内社交媒体正在逐渐兴盛,海外也不例外。在数字营销的新时代,Facebook已成为跨境电商不可或缺的平台之一。通过Facebook的巨大流量,卖家可以更好的触及潜在消费者,以实现销售增长。本文就深度拆解一下,卖家如何利用Fb…...
为啥数据需转换成tensor才能参与后续建模训练
将数据转换为Tensor(张量)格式用于深度学习和机器学习模型训练,主要是出于以下几个关键原因: 数值计算的效率:Tensor(由PyTorch、TensorFlow等库提供)是在GPU上执行高效的数值运算的数据结构。相…...
leetcode:380. O(1) 时间插入、删除和获取随机元素
实现RandomizedSet 类: RandomizedSet() 初始化 RandomizedSet 对象bool insert(int val) 当元素 val 不存在时,向集合中插入该项,并返回 true ;否则,返回 false 。bool remove(int val) 当元素 val 存在时࿰…...
Linux集群部署RabbitMQ
目录 一、准备三台虚拟机,配置相同 1、所有主机都需要hosts文件解析 2、所有主机安装erLang和rabbitmq 3、修改配置文件 4、导入rabbitmq 的管理界面 5、查看节点状态 6、设置erlang运行节点 7、rabitmq2和rabbitmq3重启服务 8、查看各个节点状态 二、添加…...
01DSP学习-了解DSP外设-以逆变器控制为例
(由于是回忆自己简单的DSP学习过程,所以博客看起来有些没有章法,请见谅~) 上一篇博客介绍了学习DSP需要的软件和硬件准备,以及一个DSP的工程包含了哪些东西。我的学习方法是目的导向,即我需要用什么我就学什么,并没有…...
【ArcGIS Pro实操第三期】多模式道路网构建(Multi-model road network construction)原理及实操案例
ArcGIS Pro实操第三期:多模式道路网构建原理及实操案例 1 概述1.1 原理 2 GIS实操2.1 新建文件并导入数据2.2 创建网络数据集2.3 设置连接策略(Setting up connectivity policies)2.4 添加成本(Adding cost attributes)…...
新建站点/网络营销管理名词解释
curl下载地址:https://curl.haxx.se/download.html,拉到页面最底下,选择红色选中的那个CAB的进行下载,如下图所示: 下载完成后,解压。 解决windows控制台curl中文乱码问题 下载iconv,地址&#…...
关键词seo排名公司/seo和sem的区别
1. 进入环境,下载附件 给的是txt文件,一堆数据,如图: 数据范围为0-255之间,且三个数据为一组,那么很容易联想到RGB图片的像素值。 2. 问题分析 我们通过代码创建一幅图,将每一行数据当做像…...
如何在交易网站做电子印章/杭州网站建设技术支持
发展新能源,落实新能源产业升级,整合能源结构调整,近日成为国家经济形势会议的一大热点。会议指出并要求需要挖掘国内市场潜力,支持新能源汽车加快发展。众昂矿业集团积极响应国家政策号召,落实绿色经济新能源产业落地…...
怎么找回网站后台密码/实体店铺引流推广方法
闲话不多说,用到vue的童鞋们应该大部分都会遇到请求中的各种奇葩问题,昨天研究一天,终于搞出来个所以然了,写篇文章拯救一下广大的童鞋们,某度娘当然也可以搜到,但一般解决了一个问题后就会出现另外一个问题…...
网站上线后/网站首页的优化
Python的信息太爆炸了吧!将纳入高考内容、小学生教材开始接触Python、Python列入全国计算机等级考试……全民学Python的话题铺天盖地,中国的Python学习者是全球第一,人才如此泛滥,甚至以后孩子都会,学习它还能体现自身…...
免费网站申请/百度手机助手app下载并安装
国战按计划进行,插7灵壁并在此集合,国战开始后很快就拿下寿春,并改7寿春雕像.这次好多了,绝大部分人都执行了命令,但还是有个别团友没有改7.吴攻寿春,被击退;龙攻许昌,也被击退.这种情况对我们很有利,许昌寿春两边刷,兄弟们想不上榜也难.可惜,人算不如天算,龙出重兵攻许昌,于是…...