当前位置: 首页 > news >正文

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系列(二)操作符

一、变换操作符&#xff1a;buffer、map、compactMap等 1.buffer buffer方法作用是缓冲组合&#xff0c;第一个参数是缓冲时间&#xff0c;第二个参数是缓冲个数&#xff0c;第三个参数是线程。缓存 Observable 中发出的新元素&#xff0c;当元素达到某个数量&#xff0c;或者…...

Gin框架简易搭建(3)--Grom与数据库

写在前面 项目地址 个人认为GORM 指南这个网站是相比较之下最为清晰的框架介绍 但是它在环境搭建阶段对于初学者而言不是很友好&#xff0c;尤其是使用mysql指令稍有不同&#xff0c;以及更新的方法和依赖问题都是很让人头疼的&#xff0c;而且这些报错并非逻辑上的&#xf…...

JavaScript模块化-CommonJS规范和ESM规范

1 ES6模块化 1.1 ES6基本介绍 ES6 模块是 ECMAScript 2015&#xff08;ES6&#xff09;引入的标准模块系统&#xff0c;广泛应用于浏览器环境下的前端开发。Node.js环境主要使用CommonJS规范。ESM使用import和export来实现模块化开发从而解决了以下问题&#xff1a; 全局作用…...

解决银河麒麟V10中的apt Lock异常

解决银河麒麟V10中的apt Lock异常 一、查找并杀掉apt进程二、删除锁文件三、重新尝试apt命令 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在使用银河麒麟V10的apt命令时&#xff0c;如果遇到lock异常&#xff0c;可以按以下步骤解决&…...

windows11环境安装lua及luarocks(踩坑篇)

一、lua安装及下载 官方地址&#xff1a; Lua Binaries Download 从这里就有坑了&#xff0c;下载后先解压win64_bin.zip&#xff0c;之后解压lib&#xff0c;用lib中的文件替换win64的&#xff0c;并把include文件夹复制过去&#xff0c;之后复制并重命名lua54&#xff0c;方…...

Glide基本用法及With方法源码解析

文章目录 引入优点 使用步骤导入依赖权限使用 其他用法占位符错误图片后备回调符圆角过渡动画大小调整gif缩略图 使用RequestOptions缓存机制设置缓存策略清理缓存 使用集成库OkHttpVolley with源码解析getRetrieverGlide.getinitializeGlide getRequestManagerRetriever Reque…...

html中的文本标签(含标签的实现案例)

目录 1.标题标签 2.标题标签的align属性 3.段落标签 4.水平线标签hr 5.换行标签br 6.文本样式标签font ​编辑7.文本格式化标签 8.文本语义标签 1&#xff09;时间time标签 2&#xff09;文本高亮Mark标签 3&#xff09;cite标签 9.特殊字符标签 10.图像标签img 附录&#xff…...

通信协议感悟

本文结合个人所学&#xff0c;简要讲述SPI&#xff0c;I2C&#xff0c;UART通信的特点&#xff0c;限制。 1.同步通信 UART&#xff0c;SPI&#xff0c;I2C三种串行通讯方式&#xff0c;SPI功能引脚为CS&#xff0c;CLK&#xff0c;MOSI&#xff0c;MISO&#xff1b;I2C功能引…...

IDEA几大常用AI插件

文章目录 前言列表GPT中文版TalkXBito AIIDEA自带的AI 前言 最近AI、GPT特别火&#xff0c;IDEA里面又有一堆插件支持GPT&#xff0c;所以做个专题比较一下各个GPT插件 列表 先看idea的plugins里支持哪些&#xff0c;搜索“GPT”之后得到的&#xff0c;我用下来感觉第一第二和…...

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一款开源的可生成逼真的人像动画的工具。它利用深度学习技术&#xff0c;根据输入的图像和音频&#xff0c;生成具有生动表情和动作的视频。用户可以通过上传照片或使用预设的模型&#xff0c;轻松创建个性化的动画内容. 以上是官网的图, 下边是本地部署生成的,效果差…...

强化学习核心概念与公式总结

强化学习核心概念与公式总结 1. 核心概念 1.1 智能体(Agent)和环境(Environment) 智能体:学习和做决策的实体环境:智能体交互的外部系统1.2 状态(State) 描述环境在特定时刻的情况1.3 动作(Action) 智能体可以执行的操作1.4 奖励(Reward) 环境对智能体动作的即时反馈1.5 策…...

基础算法--双指针【概念+图解+题解+解释】

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 本文所在专栏&#xff1a; 数据结构与算法_Stark、的博客-CSDN博客 其它专栏&#xff1a; 学习专栏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…...

如何从硬盘恢复丢失/删除的视频

您是否想知道是否可以恢复已删除的视频&#xff1f; 幸运的是&#xff0c;您可以使用奇客数据恢复从硬盘驱动器、SD 卡和 USB 闪存驱动器恢复已删除的视频文件。 你有没有遇到过这样的情况&#xff1a;当你随机删除文件以释放空间时&#xff0c;你不小心按下了一些重要视频的…...

《Effective C++》第三版——设计与声明(1)

参考资料&#xff1a; 《Effective C》第三版 注意&#xff1a;《Effective C》不涉及任何 C11 的内容&#xff0c;因此其中的部分准则可能在 C11 出现后有更好的实现方式。 条款 18&#xff1a;让接口容易被正确使用&#xff0c;不易被误用 好的接口很容易被正确使用&…...

数值计算的程序设计问题举例

### 数值计算的程序设计问题 #### 1. 结构静力分析计算 **涉及领域**&#xff1a;工程力学、建筑工程 **主要问题**&#xff1a;线性代数方程组&#xff08;Linear Algebraic Equations&#xff09; **解释说明**&#xff1a; 在结构静力分析中&#xff0c;我们需要解决复杂的…...

Java之方法的使用

修饰符 返回值 方法名称&#xff08;形式参数&#xff09;{ } 当无参数的时候形式参数中什么都不写。 列如求两个数相加 修饰符可有可无。 方法重载&#xff1a; 1.方法名相同 2.参数列表不同 3。返回值不影响重载...

sudo 命令:掌握系统权限控制,实现安全高效管理

一、命令简介 ​sudo​ 命令允许系统管理员授权普通用户执行特定命令&#xff0c;并以管理员身份运行这些命令&#xff0c;通常需要输入用户自己的密码。 ​​ sudo 全称是"substitute user do"&#xff0c;意为“替用户做”&#xff0c;也就是“以另一个用户的身…...

AndroidStudio导入so文件

点击app 右键依次选择New-Floder-JNI Floder 创建jni目录 将需要的so文件拷贝到jni目录 在app目录下&#xff0c;build.gradle文件的android{}中添加&#xff1a; sourceSets {main{jniLibs.srcDirs [src/main/jni]}}点击一下Sync Project with Gradle Files 然后编译生成AP…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

大话软工笔记—需求分析概述

需求分析&#xff0c;就是要对需求调研收集到的资料信息逐个地进行拆分、研究&#xff0c;从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要&#xff0c;后续设计的依据主要来自于需求分析的成果&#xff0c;包括: 项目的目的…...

高危文件识别的常用算法:原理、应用与企业场景

高危文件识别的常用算法&#xff1a;原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件&#xff0c;如包含恶意代码、敏感数据或欺诈内容的文档&#xff0c;在企业协同办公环境中&#xff08;如Teams、Google Workspace&#xff09;尤为重要。结合大模型技术&…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...