RxSwift:操作符
绑定操作
startWith
发出指定序列中的元素之前,先发出指定序列中的元素。
let disposeBag = DisposeBag() Observable.of("OC", "C", "Java", "C++") .startWith("1") .startWith("2") .startWith("3", "A", "B") .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) 输出: 3 A B 2 1 OC C Java C++
merge
将多个Observable合并成一个Observable,按照时间顺序发出对应的事件。
let disposeBag = DisposeBag() let subject1 = PublishSubject<String>() let subject2 = PublishSubject<String>() Observable.of(subject1, subject2) .merge() .subscribe(onNext: { print($0) }) .addDisposableTo(disposeBag) subject1.onNext("A") subject1.onNext("B") subject2.onNext("1") subject2.onNext("2") subject1.onNext("C") subject2.onNext("C") 输出: A B 1 2 C C
zip
将多个(最多8个)Observable合并成一个新的Observable。当有事件到达时,会在每个序列中对应的索引上对应的元素发出。
let disposeBag = DisposeBag()
let stringSubject = PublishSubject<String>()
let intSubject = PublishSubject<Int>()
Observable.zip(stringSubject, intSubject) { stringElement, intElement in
"\(stringElement) \(intElement)"
}.subscribe(onNext: { print($0) }).addDisposableTo(disposeBag)
stringSubject.onNext("A")
stringSubject.onNext("B")
intSubject.onNext(1)
intSubject.onNext(2)
stringSubject.onNext("C")
intSubject.onNext(3)
输出:
A 1
B 2
C 3
combineLatest
将最多8个被观察序列合并为一个新的被观察序列,当有事件到达时,会将每个序列中的最新事件发出。
let disposeBag = DisposeBag()
let stringSubject = PublishSubject<String>()
let intSubject = PublishSubject<Int>()
Observable.combineLatest(stringSubject, intSubject) { stringElement, intElement in "\(stringElement) \(intElement)"
}.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
stringSubject.onNext("A")
stringSubject.onNext("B")
intSubject.onNext(1)
intSubject.onNext(2)
stringSubject.onNext("C")
输出:
B 1
B 2
C 2
switchLatest
将被监听的被观察者转换为另一个被观察者,从最近的被观察序列中发出元素。
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "1")
let subject2 = BehaviorSubject(value: "A")
let variable = Variable(subject1)
variable.asObservable()
.switchLatest()
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
subject1.onNext("2")
subject1.onNext("3")
variable.value = subject2
subject1.onNext("4")
subject2.onNext("B")
输出:
1
2
3
A
B
转换操作
map
通过使用一个函数闭包将原来的Observable序列转换为一个新的Observable序列。
let disposeBag = DisposeBag()
Observable.of(1, 2, 3)
.map { $0 * $0 }
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
1
4
9
flatMap
将一个Observable序列转换为另一个Observable序列,并且合并两个Observable序列。会按时间顺序接收两个序列发出的元素。
let disposeBag = DisposeBag()
struct Player {
var score: Variable<Int>
}
let man = Player(score: Variable(80))
let woman = Player(score: Variable(90))
let player = Variable(man)
player.asObservable()
.flatMap { $0.score.asObservable() }
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
man.score.value = 85
player.value = woman
man.score.value = 95
woman.score.value = 100
输出:
80
85
90
95
100
flatMapLatest
flatMapLatest同flatMap一样,也是将一个序列转换为另一个序列,flatMapLatest只会从最近的序列中发出事件。flatMapLatest = map + switchLatest
let disposeBag = DisposeBag()
struct Player {
var score: Variable<Int>
}
let man = Player(score: Variable(80))
let woman = Player(score: Variable(90))
let player = Variable(man)
player.asObservable()
.flatMapLatest { $0.score.asObservable() }
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
man.score.value = 85
player.value = woman
man.score.value = 95
woman.score.value = 100
输出:
80
85
90
100
scan
scan就是提供一个初始化值,然后使用计算闭包不断将前一个元素和后一个元素进行处理,并将处理结果作为单个元素的Observable序列返回。
let disposeBag = DisposeBag()
Observable.of(10, 100, 1000)
.scan(1) { aggregateValue, newValue in
aggregateValue + newValue
}
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
11
111
1111
过滤和条件操作符
从Observable序列中挑选出发出的元素的操作。
filter
在Observable序列中只发出满足过滤条件的事件。
let disposeBag = DisposeBag()
Observable.of(
"A", "B", "C",
"D", "A", "B",
"E", "D", "A")
.filter {
$0 == "A"
}
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
A
A
A
distinctUntilChanged
禁止连续发出相同的事件。
let disposeBag = DisposeBag()
Observable.of("A", "B", "A", "A", "A", "C", "A")
.distinctUntilChanged()
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
A
B
A
C
A
elementAt
Observable序列只发出在指定位置的事件。
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.elementAt(3)
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
D
- single
只发出一个事件,若发出多个事件或不发出事件,都会发出error错误。
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.single()
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
A
Received unhandled error: /Demo/RxSwift-master/RxExample/RxExample/iOS/AppDelegate.swift:412:application(_:didFinishLaunchingWithOptions:) -> Sequence contains more than one element.
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.single { $0 == "D" }
.subscribe { print($0) }
.addDisposableTo(disposeBag)
Observable.of("A", "B", "C", "D", "B", "E")
.single { $0 == "B" }
.subscribe { print($0) }
.addDisposableTo(disposeBag)
Observable.of("A", "B", "C", "D", "E", "F")
.single { $0 == "H" }
.subscribe { print($0) }
.addDisposableTo(disposeBag)
输出:
next(D)
completed
next(B)
error(Sequence contains more than one element.)
error(Sequence doesn't contain any elements.)
take
只处理前几个信号。
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.take(3)
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
A
B
C
takeLast
只处理后几个信号。
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.takeLast(3)
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
D
E
F
takeWhile
只处理满足条件的信号。
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4, 5, 6)
.takeWhile { $0 < 4 }
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
1
2
3
takeUntil
直到另一个Observable序列发出一个信号,则原序列终止。
let disposeBag = DisposeBag()
let sourceSequence = PublishSubject<String>()
let referenceSequence = PublishSubject<String>()
sourceSequence.takeUntil(referenceSequence)
.subscribe { print($0) }
.addDisposableTo(disposeBag)
sourceSequence.onNext("A")
sourceSequence.onNext("B")
sourceSequence.onNext("C")
referenceSequence.onNext("1")
sourceSequence.onNext("E")
sourceSequence.onNext("F")
sourceSequence.onNext("G")
输出:
next(A)
next(B)
next(C)
completed
skip
跳过前几个信号。
//跳过前两个事件
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.skip(2)
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
C
D
E
F
skipWhile
跳过满足条件的事件,只要遇见不满足条件的事件,则该事件极其之后的事件(不管是否满足条件)都会发出。
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4, , 6)
.skipWhile { $0 < 4 }
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
4
5
6
skipWhileWithIndex
跳过索引满足条件的事件。
let disposeBag = DisposeBag()
Observable.of("A", "B", "C", "D", "E", "F")
.skipWhileWithIndex { element, index in
index < 3
}
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
D
E
F
skipUntil
跳过另一个Observable序列发出事件之前的所有事件。
let disposeBag = DisposeBag()
let sourceSequence = PublishSubject<String>()
let referenceSequence = PublishSubject<String>()
sourceSequence.skipUntil(referenceSequence)
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
sourceSequence.onNext("A")
sourceSequence.onNext("B")
sourceSequence.onNext("C")
referenceSequence.onNext("1")
sourceSequence.onNext("E")
sourceSequence.onNext("F")
sourceSequence.onNext("G")
输出:
E
F
G
数学和集合操作符
toArray
将一个Observable序列转化为一个数组,并转换为单一的事件信号,然后结束。
let disposeBag = DisposeBag()
Observable.range(start: 1, count: 10)
.toArray()
.subscribe { print($0) }
.addDisposableTo(disposeBag)
输出:
next([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
completed
reduce
使用一个初始值和一个操作符,对Observable序列中的所有元素进行累计操作,并转换成单一事件信号。
let disposeBag = DisposeBag()
Observable.of(10, 100, 1000)
.reduce(1, accumulator: +)
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
1111
concat
将两个序列合并成一个序列,当一个序列中的所有信号发送完成后,才后发送另一个序列中的信号。
let disposeBag = DisposeBag()
let subject1 = BehaviorSubject(value: "A")
let subject2 = BehaviorSubject(value: "1")
let variable = Variable(subject1)
variable.asObservable()
.concat()
.subscribe { print($0) }
.addDisposableTo(disposeBag)
subject1.onNext("B")
subject1.onNext("C")
variable.value = subject2
subject2.onNext("I would be ignored")
subject2.onNext("2")
subject1.onCompleted()
subject2.onNext("3")
输出:
next(A)
next(B)
next(C)
next(1)
next(2)
连接操作符
Connectable Observable在订阅时不会发出事件消息,而是仅当调用它们的connec()方法时才会发出事件消息。这样就可以等待所有我们想要的订阅者都已经订阅了以后,再开始发出事件消息,这样能保证我们想要的所有订阅者都能接收到事件消息。其实也就是等大家都就位以后,开始发出消息。
publish
将一个普通的Observable转换为一个Connectable Observable。
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance).publish()
_ = intSequence.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })
delay(2) { _ = intSequence.connect() }//把信号推迟2s发出
delay(4) {
_ = intSequence
.subscribe(onNext: { print("Subscription 2:, Event: \($0)") })
}
delay(6) {
_ = intSequence
.subscribe(onNext: { print("Subscription 3:, Event: \($0)") })
}
输出:
Subscription 1:, Event: 0
Subscription 1:, Event: 1
Subscription 1:, Event: 2
Subscription 2:, Event: 2
Subscription 1:, Event: 3
Subscription 2:, Event: 3
Subscription 1:, Event: 4
Subscription 3:, Event: 4
Subscription 2:, Event: 4
...
replay
将一个普通的sequence转换成一个connectable sequence,然后和replaySubject相似,能接收到订阅之前的事件消息。
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance).replay(5)
_ = intSequence.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })
delay(2) { _ = intSequence.connect() }
delay(4) {
_ = intSequence
.subscribe(onNext: { print("Subscription 2:, Event: \($0)") })
}
delay(8) {
_ = intSequence
.subscribe(onNext: { print("Subscription 3:, Event: \($0)") })
}
输出:
Subscription 1:, Event: 0
Subscription 1:, Event: 1
Subscription 2:, Event: 0
Subscription 2:, Event: 1
Subscription 1:, Event: 2
Subscription 2:, Event: 2
Subscription 1:, Event: 3
Subscription 2:, Event: 3
Subscription 1:, Event: 4
Subscription 2:, Event: 4
Subscription 1:, Event: 5
Subscription 2:, Event: 5
Subscription 3:, Event: 1
Subscription 3:, Event: 2
Subscription 3:, Event: 3
Subscription 3:, Event: 4
Subscription 3:, Event: 5
Subscription 1:, Event: 6
Subscription 3:, Event: 6
Subscription 2:, Event: 6
Subscription 1:, Event: 7
Subscription 3:, Event: 7
Subscription 2:, Event: 7
Subscription 1:, Event: 8
Subscription 3:, Event: 8
Subscription 2:, Event: 8
Subscription 1:, Event: 9
Subscription 3:, Event: 9
Subscription 2:, Event: 9
Subscription 1:, Event: 10
Subscription 3:, Event: 10
Subscription 2:, Event: 10
...
- multicast
将普通的Observable序列转换为connectable sequence,通过指定的subject广播事件。
let subject = PublishSubject<Int>()
_ = subject.subscribe(onNext: { print("Subject: \($0)") })
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance).multicast(subject)
_ = intSequence.subscribe(onNext: { print("\tSubscription 1:, Event: \($0)") })
delay(2) { _ = intSequence.connect() }
delay(4) {
_ = intSequence
.subscribe(onNext: { print("\tSubscription 2:, Event: \($0)") })
}
delay(6) {
_ = intSequence
.subscribe(onNext: { print("\tSubscription 3:, Event: \($0)") })
}
输出:
Subject: 0
Subscription 1:, Event: 0
Subject: 1
Subscription 1:, Event: 1
Subject: 2
Subscription 2:, Event: 2
Subscription 1:, Event: 2
Subject: 3
Subscription 2:, Event: 3
Subscription 1:, Event: 3
Subject: 4
Subscription 2:, Event: 4
Subscription 3:, Event: 4
Subscription 1:, Event: 4
Subject: 5
Subscription 2:, Event: 5
Subscription 3:, Event: 5
Subscription 1:, Event: 5
Subject: 6
Subscription 2:, Event: 6
Subscription 3:, Event: 6
Subscription 1:, Event: 6
Subject: 7
Subscription 2:, Event: 7
Subscription 3:, Event: 7
Subscription 1:, Event: 7
错误处理
帮助从一个Observable的错误通知中恢复的运算符。
catchErrorJustReturn
遇到Error事件时,输出一个指定元素,然后终止。
let disposeBag = DisposeBag()
let sequenceThatFails = PublishSubject<String>()
sequenceThatFails.catchErrorJustReturn("error!")
.subscribe { print($0) }
.addDisposableTo(disposeBag)
sequenceThatFails.onNext("A")
sequenceThatFails.onNext("B")
sequenceThatFails.onNext("C")
sequenceThatFails.onNext("D")
sequenceThatFails.onError(TestError.test)
输出:
next(A)
next(B)
next(C)
next(D)
next(error!)
completed
catchError
捕获error,并转换成指定的Observable序列对error进行处理。
let disposeBag = DisposeBag()
let sequenceThatFails = PublishSubject<String>()
let recoverySequence = PublishSubject<String>()
sequenceThatFails.catchError {
print("Error:", $0)
return recoverySequence
}.subscribe { print($0) }
.addDisposableTo(disposeBag)
sequenceThatFails.onNext("1")
sequenceThatFails.onNext("2")
sequenceThatFails.onNext("3")
sequenceThatFails.onNext("4")
sequenceThatFails.onError(TestError.test)
recoverySequence.onNext("5")
输出:
next(1)
next(2)
next(3)
next(4)
Error: test
next(5)
retry
对Error事件进行重试。
let disposeBag = DisposeBag()
var count = 1
let sequenceThatErrors = Observable<String>.create { observer in
observer.onNext("A")
observer.onNext("B")
observer.onNext("C")
if count == 1 {
observer.onError(TestError.test)
print("Error encountered")
count += 1
}
observer.onNext("D")
observer.onNext("E")
observer.onNext("F")
observer.onCompleted()
return Disposables.create()
}
sequenceThatErrors.retry()
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
A
B
C
Error encountered
A
B
C
D
E
F
- retry(_:)
指定最大的重试次数。
let disposeBag = DisposeBag()
var count = 1
let sequenceThatErrors = Observable<String>.create { observer in
observer.onNext("A")
observer.onNext("B")
observer.onNext("C")
if count < 5 {
observer.onError(TestError.test)
print("Error encountered")
count += 1
}
observer.onNext("D")
observer.onNext("E")
observer.onNext("F")
observer.onCompleted()
return Disposables.create()
}
sequenceThatErrors.retry(3)
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
A
B
C
Error encountered
A
B
C
Error encountered
A
B
C
Error encountered
Received unhandled error: /Demo/RxSwift-master/RxExample/RxExample/iOS/AppDelegate.swift:705:application(_:didFinishLaunchingWithOptions:) -> test
调试操作符
调试Rx代码的操作符
- debug
打印所有的subscriptions,events,和disposals。
let disposeBag = DisposeBag()
var count = 1
let sequenceThatErrors = Observable<String>.create { observer in
observer.onNext("A")
observer.onNext("B")
observer.onNext("C")
if count < 5 {
observer.onError(TestError.test)
print("Error encountered")
count += 1
}
observer.onNext("D")
observer.onNext("E")
observer.onNext("F")
observer.onCompleted()
return Disposables.create()
}
sequenceThatErrors.retry(3)
.debug()
.subscribe(onNext: { print($0) })
.addDisposableTo(disposeBag)
输出:
2017-01-24 15:25:40.991: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> subscribed
2017-01-24 15:25:41.013: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(A)
A
2017-01-24 15:25:41.013: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(B)
B
2017-01-24 15:25:41.013: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(C)
C
Error encountered
2017-01-24 15:25:41.014: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(A)
A
2017-01-24 15:25:41.014: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(B)
B
2017-01-24 15:25:41.014: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(C)
C
Error encountered
2017-01-24 15:25:41.015: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(A)
A
2017-01-24 15:25:41.015: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(B)
B
2017-01-24 15:25:41.015: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event next(C)
C
Error encountered
2017-01-24 15:25:41.016: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> Event error(test)
Received unhandled error: /Demo/RxSwift-master/RxExample/RxExample/iOS/AppDelegate.swift:732:application(_:didFinishLaunchingWithOptions:) -> test
2017-01-24 15:25:41.016: AppDelegate.swift:731 (application(_:didFinishLaunchingWithOptions:)) -> isDisposed
- RxSwift.Resources.total
查看RxSwift所有资源的占用,对于检查内存泄露是很有用的。
print(RxSwift.Resources.total)
let disposeBag = DisposeBag()
print(RxSwift.Resources.total)
let variable = Variable("A")
let subscription1 = variable.asObservable().subscribe(onNext: { print($0) })
print(RxSwift.Resources.total)
let subscription2 = variable.asObservable().subscribe(onNext: { print($0) })
print(RxSwift.Resources.total)
subscription1.dispose()
print(RxSwift.Resources.total)
subscription2.dispose()
print(RxSwift.Resources.total)
输出:
0
1
A
4
A
6
5
4