可监听序列
创建序列
使用Observable<>.create创建可监听序列
///typealias,别名
typealias JSON = Any
//创建一个可以被监听的json对象
let json: Observable<JSON> = Observable.create { (observer) -> Disposable in
//生成一个请求
let task = URLSession.shared.dataTask(with: ...) { data, _, error in
//如果error不为空,请求失败,发送error事件
guard error == nil else {
observer.onError(error!)
return
}
//json解析失败时,同样发送error事件
guard let data = data,
let jsonObject = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
else {
observer.onError(DataError.cantParseJSON)
return
}
//拿到请求数据后发送next事件,表示继续往下走,如果还有其它的onNext事件,可以继续触发
observer.onNext(jsonObject)
//所有onNext发送完成之后,触发onCompleted事件,表示任务结束
observer.onCompleted()
}
task.resume()
//如果数据绑定被清除,则取消请求
return Disposables.create { task.cancel() }
}
如何使用刚刚创建的json:
//subscribe订阅这个对象
json.subscribe(
//onNext事件观察者
onNext: { json in
print("取得 json 成功: \(json)")
}, onError: { error in
print("取得 json 失败 Error: \(error.localizedDescription)")
}, onCompleted: {
print("取得 json 任务成功完成")
})
//disposeBag与某个对象的生命周期绑定,当对象销毁时,销毁disposeBag,同时清除数据绑定
.disposed(by: disposeBag)
Observable的特性:
- 多元素:可以有多个onNext
- 共享附加作用:
使用Single<>.create创建可监听序列
//创建一个方法,返回一个Single对象
func getRepo(_ repo: String) -> Single<[String: Any]> {
//创建一个Single对象并返回
return Single<[String: Any]>.create { single in
let url = URL(string: "https://api.github.com/repos/\(repo)")!
let task = URLSession.shared.dataTask(with: url) {
data, _, error in
if let error = error {
single(.error(error))
return
}
guard let data = data,
let json = try? JSONSerialization.jsonObject(with: data, options: .mutableLeaves),
let result = json as? [String: Any] else {
single(.error(DataError.cantParseJSON))
return
}
//single只能发送单一的success事件,无法像Observable一样发送多个onNext事件
single(.success(result))
//因为只能发送一个success事件,所以无需onCompleted来表示已完成
}
task.resume()
return Disposables.create { task.cancel() }
}
}
如何使用刚刚创建的getRepo方法:
getRepo("ReactiveX/RxSwift")
.subscribe(onSuccess: { json in
print("JSON: ", json)
}, onError: { error in
print("Error: ", error)
})
.disposed(by: disposeBag)
Single的特性:
- 单元素:只有一个onSuccess
- 不共享附加作用:每次subscribe订阅,都会触发请求
- 可以对
Observable调用.asSingle()方法,将它转换为Single
使用Completable.create创建可监听序列
func cacheLocally() -> Completable {
return Completable.create { completable in
// Store some data locally
...
...
guard success else {
completable(.error(CacheError.failedCaching))
return Disposables.create {}
}
completable(.completed)
return Disposables.create {}
}
}
如何使用刚刚创建的cacheLocally方法:
cacheLocally()
.subscribe(onCompleted: {
print("Completed with no error")
}, onError: { error in
print("Completed with an error: \(error.localizedDescription)")
})
.disposed(by: disposeBag)
Bag)
Completable的特性:
- 单元素:只有一个onCompleted
- 不共享附加作用:每次subscribe订阅,都会触发请求
- onCompleted不带参数
使用Maybe<>.create创建可监听序列
func generateString() -> Maybe<String> {
return Maybe<String>.create { maybe in
//要么返回一个success事件,可以带参数
maybe(.success("RxSwift"))
// OR
//要么返回一个completed事件
maybe(.completed)
// OR
//要么返回一个error事件
maybe(.error(error))
return Disposables.create {}
}
}
使用:
generateString()
.subscribe(onSuccess: { element in
print("Completed with element \(element)")
}, onError: { error in
print("Completed with an error \(error.localizedDescription)")
}, onCompleted: {
print("Completed with no element")
})
.disposed(by: disposeBag)
Maybe的特性:
- 单元素:只会触发三个元素中的一个
- 不共享附加作用:每次subscribe订阅,都会触发请求
- onCompleted不带参数
使用Driver简化UI层的代码
使用Driver的序列具有以下特征
- 不会产生 error 事件
- 一定在 MainScheduler 监听(主线程监听)
- 共享附加作用
为什么要使用Driver?
Driver表示这个序列不会产生错误事件,并且一定在主线程监听,非常适合用来绑定UI元素.
因为如果在其它线程刷新UI,会导致崩溃.
例:在searchBar搜索框里输入文本,然后发请求,把请求结果展示在tableView里,并把结果个数显示在Label里.
代码如下:
let results = searchBar.rx.text
.throttle(0.3, scheduler: MainScheduler.instance)
.flatMapLatest { searchBar in
//发请求
fetchAutoCompleteItems(searchBar)
}
results
.map { "\($0.count)" }
.bind(to: resultCountLabel.rx.text)
.disposed(by: disposeBag)
results
.bind(to: resultsTableView.rx.items(cellIdentifier: "Cell")) {
(_, result, cell) in
cell.textLabel?.text = "\(result)"
}
.disposed(by: disposeBag)
这段代码存在着如下问题:
fetchAutoCompleteItems()请求失败时,会导致序列中断,并不会刷新UI;- 请求结果返回时,如果不在主线程,那么刷新UI会导致崩溃;
- 返回结果bindTo两个UI元素上,如果没有共享附加作用,比如fetchAutoCompleteItems()是用Single创建的,那么就会发两次请求;
以上3点不符合driver序列,改造后代码如下:
let results = query.rx.text
.throttle(0.3, scheduler: MainScheduler.instance)
.flatMapLatest { query in
fetchAutoCompleteItems(query)
.observeOn(MainScheduler.instance) // 结果在主线程返回
//如果请求失败,那么处理错误保证序列继续往下进行
//可以理解为,把本来该走.onError()事件,改为走.onSuccess([])
.catchErrorJustReturn([])
}
//share表示共享附加作用,这里指共享网络请求
.share(replay: 1) // HTTP 请求是被共享的
results
.map { "\($0.count)" }
.bind(to: resultCount.rx.text)
.disposed(by: disposeBag)
results
.bind(to: resultsTableView.rx.items(cellIdentifier: "Cell")) {
(_, result, cell) in
cell.textLabel?.text = "\(result)"
}
.disposed(by: disposeBag)
经过复杂的处理后,解决了上述问题,但是写法太过复杂,容易出错.直接改用Driver写法,如下:
/**
asDriver()将普通序列转换成Driver序列,该序列会强制满足Driver3要素,避免了手动处理;
*/
let results = query.rx.text.asDriver() // 将普通序列转换为 Driver
.throttle(0.3, scheduler: MainScheduler.instance)
.flatMapLatest { query in
fetchAutoCompleteItems(query)
//如果序列本身包含了Error事件,需要使用onErrorJustReturn: 提供抛错时的默认返回值
.asDriver(onErrorJustReturn: [])
}
results
.map { "\($0.count)" }
.drive(resultCount.rx.text) // 这里改用 `drive` 而不是 `bindTo`
.disposed(by: disposeBag) // 这样可以确保必备条件都已经满足了
results
.drive(resultsTableView.rx.items(cellIdentifier: "Cell")) {
(_, result, cell) in
cell.textLabel?.text = "\(result)"
}
.disposed(by: disposeBag)
使用Signal处理事件序列
Signal 和 Driver 相似,唯一的区别是,Driver 会对新观察者回放(重新发送)上一个元素,而 Signal 不会对新观察者回放上一个元素。
let button: UIButton = ...
let showAlert: (String) -> Void = ...
let event: Driver<Void> = button.rx.tap.asDriver()
let observer: () -> Void = { showAlert("弹出提示框1") }
event.drive(onNext: observer)
// ... 假设以下代码是在用户点击 button 后运行
let newObserver: () -> Void = { showAlert("弹出提示框2") }
//使用Driver时,会接受Button上一次的点击事件,从而触发newObserver
event.drive(onNext: newObserver)
使用Driver时,会接受Button上一次的点击事件,从而触发newObserver.这里应该用Signal:
...
let event: Signal<Void> = button.rx.tap.asSignal()
let observer: () -> Void = { showAlert("弹出提示框1") }
event.emit(onNext: observer)
// ... 假设以下代码是在用户点击 button 后运行
let newObserver: () -> Void = { showAlert("弹出提示框2") }
event.emit(onNext: newObserver)
Signal不管订阅的对象在之前已经发送了多少事件,只管在订阅后发送的事件
Driver使用.asDriver()转换,使用.drive()订阅;Signal使用.asSignal()转换,使用.emit()订阅
使用ControlProperty描述UI 的属性(既是可监听序列又是观察者)
ControlProperty特征
- 不会产生 error 事件
- 一定在 MainScheduler 订阅(主线程订阅)
- 一定在 MainScheduler 监听(主线程监听)
- 共享状态变化
可以用来把自定义UI控件的某个属性,描述为可被监听的属性:
比如RxSwift把UITextField的text设置为可被监听的属性
import RxSwift
import UIKit
extension Reactive where Base: UITextField {
public var text: ControlProperty<String?> {
return value
}
public var value: ControlProperty<String?> {
return base.rx.controlPropertyWithDefaultEvents(
getter: { textField in
textField.text
},
setter: { textField, value in
if textField.text != value {
textField.text = value
}
}
)
}
//......
}
使用ControlEvent描述UI 所产生的事件
ControlEvent特征和ControlProperty一致
可以用来把自定义UI控件的某个方法,描述为可被监听的方法:
比如UIButton 的 rx.tap 方法类型便是 ControlEvent:
import RxSwift
import UIKit
extension Reactive where Base: UIButton {
public var tap: ControlEvent<Void> {
return controlEvent(.touchUpInside)
}
}
用ControlEvent来重写UIViewController的生命周期,方便监听:
import UIKit
import RxCocoa
import RxSwift
public extension Reactive where Base: UIViewController {
public var viewDidLoad: ControlEvent<Void> {
//调用父类的viewDidLoad方法
let source = self.methodInvoked(#selector(Base.viewDidLoad)).map { _ in }
return ControlEvent(events: source)
}
}
使用时:
//页面加载完毕
self.rx.viewDidLoad
.subscribe(onNext: {
print("viewDidLoad")
}).disposed(by: disposeBag)
如何选择可监听序列的创建方式
Observable
适用于需要监听多个元素的情况,如:
空调温度,20度时开制热,30度时开制冷,等
Single
适用于要么成功要么失败,并且成功时能拿到数据的情况,比如网络请求
Completable
同样适用于要么成功要么失败,但是并不关心成功时的返回值的情况,比如文件处理.
Maybe
适用于要么成功要么失败,可能需要参数,也可能不需要参数的情况.
Driver
适用于UI元素状态的处理,比如更新文本.
Signal
适用于UI元素事件的处理,比如按钮点击.
ControlProperty
适用与把自定义UI的属性注册为被观察者
ControlEvent
适用与把自定义UI的方法注册为被观察者
观察者
订阅某个序列后,触发信号时需要执行的动作
AnyObserver
通常的写法是:
URLSession.shared.rx.data(request: URLRequest(url: url))
.subscribe(onNext: { data in
print("Data Task Success with count: \(data.count)")
}, onError: { error in
print("Data Task Error: \(error)")
})
.disposed(by: disposeBag)
.subscribe()里面的,就是观察者:
let observer: AnyObserver<Data> = AnyObserver { (event) in
switch event {
case .next(let data):
print("Data Task Success with count: \(data.count)")
case .error(let error):
print("Data Task Error: \(error)")
default:
break
}
}
URLSession.shared.rx.data(request: URLRequest(url: url))
.subscribe(observer)
.disposed(by: disposeBag)
Binder
Binder因为具有以下特征:
- 不会处理错误事件
- 确保绑定都是在给定 Scheduler 上执行(默认 MainScheduler)
常用来创建创建UI观察者
- 按钮是否可点击
button.rx.isEnabled:
extension Reactive where Base: UIControl {
public var isEnabled: Binder<Bool> {
return Binder(self.base) { control, value in
control.isEnabled = value
}
}
}
- label 的当前文本
label.rx.text:
extension Reactive where Base: UILabel {
public var text: Binder<String?> {
return Binder(self.base) { label, text in
label.text = text
}
}
}
Observable & Observer 既是可监听序列也是观察者
辅助类型既是观察者也是可监听序列,能对Observable做相应的约束,满足自己应用的要求
AsyncSubject(最后一个元素)
AsyncSubject 将在源 Observable 产生完成事件后,发出最后一个元素(仅仅只有最后一个元素)
演示:
let disposeBag = DisposeBag()
let subject = AsyncSubject<String>()
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("🐶")
subject.onNext("🐱")
subject.onNext("🐹")
subject.onCompleted()
输出结果:
Subscription: 1 Event: next(🐹)
Subscription: 1 Event: completed
PublishSubject(订阅后产生的元素)
PublishSubject 将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者
演示:
let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("🐶")
subject.onNext("🐱")
subject
.subscribe { print("Subscription: 2 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("🅰️")
subject.onNext("🅱️")
输出结果:
Subscription: 1 Event: next(🐶)
Subscription: 1 Event: next(🐱)
Subscription: 1 Event: next(🅰️)
Subscription: 2 Event: next(🅰️)
Subscription: 1 Event: next(🅱️)
Subscription: 2 Event: next(🅱️)
ReplaySubject(全部或者订阅前指定要求的元素)
ReplaySubject 将对观察者发送全部的元素,无论观察者是何时进行订阅的。
这里存在多个版本的 ReplaySubject,有的只会将最新的 n 个元素发送给观察者,有的只会将限制时间段内最新的元素发送给观察者。
演示:
let disposeBag = DisposeBag()
let subject = ReplaySubject<String>.create(bufferSize: 1)
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("🐶")
subject.onNext("🐱")
subject
.subscribe { print("Subscription: 2 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("🅰️")
subject.onNext("🅱️")
输出结果:
Subscription: 1 Event: next(🐶)
Subscription: 1 Event: next(🐱)
Subscription: 2 Event: next(🐱)
Subscription: 1 Event: next(🅰️)
Subscription: 2 Event: next(🅰️)
Subscription: 1 Event: next(🅱️)
Subscription: 2 Event: next(🅱️)
BehaviorSubject(最新的元素,没有就默认)
演示:
let disposeBag = DisposeBag()
let subject = BehaviorSubject(value: "🔴")
subject
.subscribe { print("Subscription: 1 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("🐶")
subject.onNext("🐱")
subject
.subscribe { print("Subscription: 2 Event:", $0) }
.disposed(by: disposeBag)
subject.onNext("🅰️")
subject.onNext("🅱️")
输出结果:
Subscription: 1 Event: next(🔴)
Subscription: 1 Event: next(🐶)
Subscription: 1 Event: next(🐱)
Subscription: 2 Event: next(🐱)
Subscription: 1 Event: next(🅰️)
Subscription: 2 Event: next(🅰️)
Subscription: 1 Event: next(🅱️)
Subscription: 2 Event: next(🅱️)
Subscription: 3 Event: next(🅱️)
ControlProperty(描述 UI 控件属性)
辅助类型使用时,如果源Observable因为产生了error事件而终止,那么辅助类型就不会发出任何元素而是发出error事件
Variable(弃用)
Operator - 操作符
创建
create 自定义逻辑
create 操作符将创建一个 Observable,你需要提供一个构建函数,在构建函数里面描述事件(next,error,completed)的产生过程。
deferred 每次订阅时创建
直到订阅发生,才创建 Observable,并且为每位订阅者创建全新的 Observable
empty 只有一个完成事件
创建一个只有一个完成事件的Observable。 演示:
let id = Observable<Int>.empty()
//相当于
let id = Observable<Int>.create { observer in
observer.onCompleted()
return Disposables.create()
}
error 只有error事件
创建一个只有 error 事件的 Observable. 演示:
let error: Error = ...
let id = Observable<Int>.error(error)
//相当于
let id = Observable<Int>.create { observer in
observer.onError(error)
return Disposables.create()
}
never 永远不会发出元素
创建一个永远不会发出元素的 Observable 演示:
let id = Observable<Int>.never()
//相当于
let id = Observable<Int>.create { observer in
return Disposables.create()
}
repeatElement 重复的产生某一个元素
repeatElement 操作符将创建一个 Observable,这个 Observable 将无止尽的发出同一个元素。
演示:
let id = Observable.repeatElement(0)
//相当于
let id = Observable<Int>.create { observer in
observer.onNext(0)
observer.onNext(0)
observer.onNext(0)
observer.onNext(0)
... // 无数次
return Disposables.create()
}
just 产生特定的一个元素
创建 Observable 发出唯一的一个元素 演示:
let id = Observable.just(0)
//相当于
let id = Observable<Int>.create { observer in
observer.onNext(0)
observer.onCompleted()
return Disposables.create()
}
from 从一个序列拉取元素
将其他类型或者数据结构转换为 Observable; 演示:
//将数组转换成Observable
let numbers = Observable.from([0, 1, 2])
//相当于
let numbers = Observable<Int>.create { observer in
observer.onNext(0)
observer.onNext(1)
observer.onNext(2)
observer.onCompleted()
return Disposables.create()
}
let optional: Int? = 1
//将可选值转换成Observable
let value = Observable.from(optional: optional)
//相当于
let value = Observable<Int>.create { observer in
if let element = optional {
observer.onNext(element)
}
observer.onCompleted()
return Disposables.create()
}
interval 定时
创建一个 Observable 每隔一段时间,发出一个索引数; interval 操作符将创建一个 Observable,它每隔一段设定的时间,发出一个索引数的元素。它将发出无数个元素。 演示:
//创建一个Observable:主线程的秒定时器,每秒发送一个next
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//publish待连接,连接前不会发送next,
.publish()
//订阅,因为没有connect,即使订阅也不会发送next
_ = intSequence
.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })
//2秒之后,开始连接,定时器开始发next事件
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
_ = intSequence.connect()
}
//4秒之后,增加一个订阅
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
_ = intSequence
.subscribe(onNext: { print("Subscription 2:, Event: \($0)") })
}
//6秒之后,增加一个订阅
DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
_ = intSequence
.subscribe(onNext: { print("Subscription 3:, Event: \($0)") })
}
timer 延时
- 创建一个 Observable 在一段延时后,产生唯一的一个元素
- 创建一个 Observable 在一段延时后,每隔一段时间产生一个元素
组合Observables
merge 任意一个 Observable 产生了元素,就发出这个元素
将多个 Observables 合并成一个;
通过使用 merge 操作符你可以将多个 Observables 合并成一个,当某一个 Observable 发出一个元素时,他就将这个元素发出。
注意⚠️:如果,某一个 Observable 发出一个 onError 事件,那么被合并的 Observable 也会将它发出,并且立即终止序列。
演示:
let disposeBag = DisposeBag()
let subject1 = PublishSubject<String>()
let subject2 = PublishSubject<String>()
Observable.of(subject1, subject2)
.merge()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
subject1.onNext("🅰️")
subject1.onNext("🅱️")
subject2.onNext("①")
subject2.onNext("②")
subject1.onNext("🆎")
subject2.onNext("③")
输出:
🅰️
🅱️
①
②
🆎
③
concat 当前Observable发完后下一个才发出
concat 操作符将多个 Observables 按顺序串联起来,当前一个 Observable 元素发送完毕后,后一个 Observable 才可以开始发出元素。
concat 将等待前一个 Observable 产生完成事件后,才对后一个 Observable 进行订阅。如果后一个是“热” Observable ,在它前一个 Observable 产生完成事件前,所产生的元素将不会被发送出来。 演示:
let disposeBag = DisposeBag()
//发送上一个 event 以及之后新创建的 event
let subject1 = BehaviorSubject(value: "🍎")
let subject2 = BehaviorSubject(value: "🐶")
//发送上一个 event 以及之后新创建的 event,subject1和subject2在这里作为可监听序列被监听
let variable = Variable(subject1)
//订阅subject1时,发送上一个event🍎
variable.asObservable()
//如果不加concat,print出来就是subject1自身,而不是🍎
.concat()
.subscribe { print($0) }
.disposed(by: disposeBag)
//发送最新的event🍐
subject1.onNext("🍐")
//发送最新的event🍊
subject1.onNext("🍊")
//修改value时,等于订阅subject2,发出默认event🐶
variable.value = subject2
//subject2发出event,但是由于concat特性,subject1还没onCompleted,所以subject2并不会触发观察者print
subject2.onNext("I would be ignored")
//BehaviorSubject特性:subject2发出的I would be ignored事件没有被监听,就被🐱覆盖
subject2.onNext("🐱")
//subject1结束后,concat特性:会自动走subject2序列,这个时候,会发送subject2上一个 event🐱 以及之后新创建的 event🐭
subject1.onCompleted()
subject2.onNext("🐭")
//variable销毁时,会自动发送onCompleted
输出结果:
next(🍎)
next(🍐)
next(🍊)
next(🐱)
next(🐭)
组合多个 Observables 的元素
zip 当每一个 Observable 都发出一个新的元素
通过一个函数将多个 Observables 的元素组合起来,然后将每一个组合的结果发出来
- 最多不超过8个Observables
- 严格的按照序列的索引数进行组合。例如,返回的 Observable 的第一个元素,是由每一个源 Observables 的第一个元素组合出来的。它的第二个元素 ,是由每一个源 Observables 的第二个元素组合出来的。它的第三个元素 ,是由每一个源 Observables 的第三个元素组合出来的,以此类推。
- 它的元素数量等于源 Observables 中元素数量最少的那个。
演示:
let disposeBag = DisposeBag()
let first = PublishSubject<String>()
let second = PublishSubject<String>()
Observable.zip(first, second) { $0 + $1 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
first.onNext("1")
second.onNext("A")
first.onNext("2")
second.onNext("B")
second.onNext("C")
second.onNext("D")
first.onNext("3")
first.onNext("4")
输出:
1A
2B
3C
4D
combineLatest 任意一个 Observable 发出一个新的元素
combineLatest 操作符将多个 Observables 中最新的元素通过一个函数组合起来,然后将这个组合的结果发出来。这些源 Observables 中任何一个发出一个元素,他都会发出一个元素(前提是,这些 Observables 曾经发出过元素)。
演示:
let disposeBag = DisposeBag()
let first = PublishSubject<String>()
let second = PublishSubject<String>()
Observable.combineLatest(first, second) { $0 + $1 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
first.onNext("1")
second.onNext("A")
first.onNext("2")
second.onNext("B")
second.onNext("C")
second.onNext("D")
first.onNext("3")
first.onNext("4")
输出结果:
1A
2A
2B
2C
2D
3D
4D
转换
map 对每个元素直接转换
将源 Observable 的每一个元素应用一个转换方法,将他们转换成 另一个元素。 演示:
struct Person {
var name:String!
var age:Int!
init(dic:Dictionary<String,Any>) {
self.name = dic["name"] as? String
self.age = dic["age"] as? Int
}
}
let disposeBag = DisposeBag()
let arr:[Dictionary<String,Any>] = [
["name":"张三","age":23],
["name":"李四","age":33],
["name":"王五","age":22],]
Observable.from(arr)
.map { Person.init(dic: $0) }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
Person(name: Optional("张三"), age: Optional(23))
Person(name: Optional("李四"), age: Optional(33))
Person(name: Optional("王五"), age: Optional(22))
这里将Dictionary元素转换成了Person结构体
flatMap 转换到另一个 Observable
flatMap 操作符将源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。 然后将这些 Observables 的元素合并之后再发送出来。
例如,当 Observable 的元素本身拥有其他的 Observable 时,你可以将所有子 Observables 的元素发送出来。
演示:
let A = BehaviorSubject(value: "A的默认消息")
let B = BehaviorSubject(value: "B的默认消息")
Observable.of(A,B)//同时观察了A,B
.flatMap {$0} //将Observable的元素转换成其他的Observable",把对 A/B 的观察" 转成 "A/B 观察的字符串"
.subscribe(onNext: {print($0)})
.disposed(by: disposeBag)
A.onNext("A-2")
A.onNext("A-3")
B.onNext("B-2")
B.onNext("B-3")
B.onNext("B-4")
输出:
A的默认消息
B的默认消息
A-2
A-3
B-2
B-3
B-4
flatMapLatest 只接收最新的元素转换的 Observable 所产生的元素
将 Observable 的元素转换成其他的Observable,然后取这些 Observables中最新的一个。 flatMapLatest操作符将源Observable 的每一个元素应用一个转换方法,将他们转换成Observables。一旦转换出一个新的 Observable,就只发出它的元素,旧的 Observables的元素将被忽略掉。 演示:
let A = BehaviorSubject(value: "A的默认消息")
let B = BehaviorSubject(value: "B的默认消息")
Observable.of(A,B)
.flatMapLatest {$0}
.subscribe(onNext: {print($0)})
.disposed(by: disposeBag)
A.onNext("A-2")
A.onNext("A-3")
B.onNext("B-2")
B.onNext("B-3")
B.onNext("B-4")
输出结果:
A的默认消息
B的默认消息
B-2
B-3
B-4
concatMap 每一个元素转换的 Observable 按顺序产生元素
concatMap 操作符将源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables。然后让这些 Observables 按顺序的发出元素,当前一个 Observable 元素发送完毕后,后一个 Observable 才可以开始发出元素。等待前一个 Observable 产生完成事件后,才对后一个 Observable 进行订阅。 演示:
...
variable.asObservable()
//将subject1的元素,通过{$0}转换成Observables
.concatMap{$0}
.subscribe { print($0) }
.disposed(by: disposeBag)
输出结果没变:
next(🍎)
next(🍐)
next(🍊)
next(🐱)
next(🐭)
concatMap 和 concat 的区别:
concatMap:将源 Observable 的每一个元素应用一个转换方法,将他们转换成 Observables
concat:操作符将多个 Observables 按顺序串联起来
将产生的事件封装成元素发送出来
materialize
将序列产生的事件,转换成元素 演示:
let disposeBag = DisposeBag()
Observable.of(1,2,3)
.materialize()
.subscribe(onNext:{print($0)})
.disposed(by: disposeBag)
输出:
next(1)
next(2)
next(3)
completed
dematerialize
将 materialize 转换后的元素还原 演示:
let disposeBag = DisposeBag()
Observable.of(1,2,3)
.materialize()
.dematerialize()
.subscribe(onNext:{print($0)})
.disposed(by: disposeBag)
输出:
1
2
3
延迟
delay 延迟发出元素
将 Observable 的每一个元素拖延一段时间后发出
delaySubscription 延迟订阅
延时订阅.delaySubscription 操作符将在经过所设定的时间后,才对 Observable 进行订阅操作。
delay是延时发元素,delaySubscription是延时订阅
过滤元素
filter 通过判定条件过滤出一些元素
filter 操作符将通过你提供的判定方法过滤一个 Observable。 演示:
let disposeBag = DisposeBag()
Observable.of(2, 30, 22, 5, 60, 1)
.filter { $0 > 10 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
30
22
60
take 只取头 n 个元素
只发出头 n 个元素。并且忽略掉后面的元素,直接结束序列。 演示:
let disposeBag = DisposeBag()
Observable.of("🐱", "🐰", "🐶", "🐸", "🐷", "🐵")
.take(3)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
🐱
🐰
🐶
takeLast 只取尾 n 个元素
只发出尾部 n 个元素。并且忽略掉前面的元素。 演示:
let disposeBag = DisposeBag()
Observable.of("🐱", "🐰", "🐶", "🐸", "🐷", "🐵")
.takeLast(3)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
🐸
🐷
🐵
takeUntil 只取第二个Observable发出元素前发出的元素
忽略掉在第二个 Observable 产生事件后发出的那部分元素
takeUntil 操作符将镜像源 Observable,它同时观测第二个 Observable。一旦第二个 Observable 发出一个元素或者产生一个终止事件,那个镜像的 Observable 将立即终止。
演示:
let disposeBag = DisposeBag()
let sourceSequence = PublishSubject<String>()
let referenceSequence = PublishSubject<String>()
sourceSequence
.takeUntil(referenceSequence)
.subscribe { print($0) }
.disposed(by: disposeBag)
sourceSequence.onNext("🐱")
sourceSequence.onNext("🐰")
sourceSequence.onNext("🐶")
referenceSequence.onNext("🔴")
sourceSequence.onNext("🐸")
sourceSequence.onNext("🐷")
sourceSequence.onNext("🐵")
输出:
next(🐱)
next(🐰)
next(🐶)
completed
takeWhile 只取判定为true的元素
镜像一个 Observable 直到某个元素的判定为 false
takeWhile 操作符将镜像源 Observable 直到某个元素的判定为 false。此时,这个镜像的 Observable 将立即终止。
演示:
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4, 3, 2, 1)
.takeWhile { $0 < 4 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
1
2
3
amb 从多个 Observables 中,只取第一个产生元素的 Observable
在多个源 Observables 中, 取第一个发出元素或产生事件的 Observable,然后只发出它的元素
elementAt 只取第n个元素
只发出 Observable 中的第 n 个元素;elementAt 操作符将拉取 Observable 序列中指定索引数的元素,然后将它作为唯一的元素发出。 演示:
let disposeBag = DisposeBag()
Observable.of(1,2,3)
.elementAt(1)
.subscribe(onNext:{print($0)})
.disposed(by: disposeBag)
输出:
2
sample 通过另一个Observable对源抽样取元素
sample 操作符将不定期的对源 Observable 进行取样操作。通过第二个 Observable 来控制取样时机。一旦第二个 Observable 发出一个元素,就从源 Observable 中取出最后产生的元素。
debounce 在指定时间内只接受最新数据
debounce 操作符将发出过滤元素,在指定时间内,只接受最新数据 演示:
let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
subject
.debounce(.seconds(2), scheduler: MainScheduler.instance)
.subscribe {
print("Subscription: 1 Event:", $0)
}
.disposed(by: disposeBag)
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
subject.onNext("🐱")
输出结果:
==实际测试时无任何输出,原因不明==
distinctUntilChanged 直到元素的值发生变化才发出新的元素
阻止 Observable 发出相同的元素。如果后一个元素和前一个元素是相同的,那么这个元素将不会被发出来。如果后一个元素和前一个元素不相同,那么这个元素才会被发出来。 演示:
let disposeBag = DisposeBag()
Observable.of("🐱", "🐷", "🐱", "🐱", "🐱", "🐵", "🐱")
.distinctUntilChanged()
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
🐱
🐷
🐱
🐵
🐱
skip 跳过头 n 个元素
skip 操作符可以让你跳过 Observable 中头 n 个元素,只关注后面的元素。 演示:
let disposeBag = DisposeBag()
Observable.of("🐱", "🐰", "🐶", "🐸", "🐷", "🐵")
.skip(2)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
🐶
🐸
🐷
🐵
skipUntil 跳过头几个元素直到另一个 Observable 发出一个元素
跳过 Observable 中头几个元素,直到另一个 Observable 发出一个元素。
skipUntil 操作符可以让你忽略源 Observable 中头几个元素,直到另一个 Observable 发出一个元素后,它才镜像源 Observable。
演示:
let disposeBag = DisposeBag()
let sourceSequence = PublishSubject<String>()
let referenceSequence = PublishSubject<String>()
sourceSequence
.skipUntil(referenceSequence)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
sourceSequence.onNext("🐱")
sourceSequence.onNext("🐰")
sourceSequence.onNext("🐶")
referenceSequence.onNext("🔴")
sourceSequence.onNext("🐸")
sourceSequence.onNext("🐷")
sourceSequence.onNext("🐵")
输出:
🐸
🐷
🐵
skipWhile 跳过判定为true的元素
skipWhile 操作符可以让你忽略源 Observable 中头几个元素,直到元素的判定为否后,它才镜像源 Observable。 演示:
let disposeBag = DisposeBag()
Observable.of(1, 2, 3, 4, 3, 2, 1)
.skipWhile { $0 < 4 }
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
4
3
2
1
ignoreElements 忽略所有next的元素
忽略掉所有的元素,只发出 error 或 completed 事件; ignoreElements 操作符将阻止 Observable 发出 next 事件,但是允许他发出 error 或 completed 事件。
startWith 头部插入元素
startWith 操作符会在 Observable 头部插入一些元素。 演示:
let disposeBag = DisposeBag()
Observable.of("🐶", "🐱", "🐭", "🐹")
.startWith("1")
.startWith("2", "🅰️️")
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
2
🅰️
1
🐶
🐱
🐭
🐹
publish 通知可被连接后才发出元素
publish 会将 Observable 转换为可被连接的 Observable。可被连接的 Observable 和普通的 Observable 十分相似,不过在被订阅后不会发出元素,直到 connect 操作符被应用为止。这样一来你可以控制 Observable 在什么时候开始发出元素。
connect 通知可被连接
connect 通知可被连接的 Observable可以发出元素了
演示:
//创建一个Observable:主线程的秒定时器,每秒发送一个next
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//publish待连接,连接前不会发送next,
.publish()
//订阅,因为没有connect,即使订阅也不会发送next
_ = intSequence
.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })
//2秒之后,开始连接,定时器开始发next事件
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
_ = intSequence.connect()
}
//4秒之后,增加一个订阅
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
_ = intSequence
.subscribe(onNext: { print("Subscription 2:, Event: \($0)") })
}
//6秒之后,增加一个订阅
DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
_ = intSequence
.subscribe(onNext: { print("Subscription 3:, Event: \($0)") })
}
refCount 与publish相反
将可被连接的 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)") })
}
缓存/组合元素
buffer 数量或时间
buffer 操作符将缓存 Observable 中发出的新元素,当元素达到某个数量,或者经过了特定的时间,它就会将这个元素集合发送出来。
window
将 Observable 分解为多个子 Observable,周期性的将子 Observable 发出来
window 操作符和 buffer 十分相似,buffer 周期性的将缓存的元素集合发送出来,而 window 周期性的将元素集合以 Observable 的形态发送出来。 buffer 要等到元素搜集完毕后,才会发出元素序列。而 window 可以实时发出元素序列。
groupBy
groupBy 操作符将源 Observable 分解为多个子 Observable,然后将这些子 Observable 发送出来。 也就是说该操作符会将元素通过某个键进行分组,然后将分组后的元素序列以 Observable 的形态发送出来。 演示:
let disposeBag = DisposeBag()
//将奇数偶数分成两组
Observable<Int>.of(0, 1, 2, 3, 4, 5)
.groupBy(keySelector: { (element) -> String in
return element % 2 == 0 ? "偶数" : "基数"
})
.subscribe(onNext: { (group) in
group.subscribe(onNext: { (x) in
print("key:\(group.key) event:\(x)")
})
.disposed(by: disposeBag)
})
.disposed(by: disposeBag)
输出:
key:偶数 event:0
key:基数 event:1
key:偶数 event:2
key:基数 event:3
key:偶数 event:4
key:基数 event:5
错误处理
catchError 拦截错误事件
catchError 操作符将会拦截一个 error 事件,将它替换成其他的元素或者一组元素,然后传递给观察者。这样可以使得 Observable 正常结束,或者根本都不需要结束。
这里存在其他版本的 catchError 操作符。 演示:
let disposeBag = DisposeBag()
let sequenceThatFails = PublishSubject<String>()
let recoverySequence = PublishSubject<String>()
sequenceThatFails
.catchError {
print("Error:", $0)
//这里的return 把当前序列替换成了recoverySequence
return recoverySequence
}
.subscribe { print($0) }
.disposed(by: disposeBag)
sequenceThatFails.onNext("😬")
sequenceThatFails.onNext("😨")
sequenceThatFails.onNext("😡")
sequenceThatFails.onNext("🔴")
sequenceThatFails.onError(TestError.test)
recoverySequence.onNext("😊")
输出结果:
next(😬)
next(😨)
next(😡)
next(🔴)
Error: test
next(😊)
catchErrorJustReturn 拦截错误事件并结束序列
catchErrorJustReturn 操作符会将error 事件替换成其他的一个元素,然后结束该序列。 演示:
let disposeBag = DisposeBag()
let sequenceThatFails = PublishSubject<String>()
sequenceThatFails
.catchErrorJustReturn("😊")
.subscribe { print($0) }
.disposed(by: disposeBag)
sequenceThatFails.onNext("😬")
sequenceThatFails.onNext("😨")
sequenceThatFails.onNext("😡")
sequenceThatFails.onNext("🔴")
sequenceThatFails.onError(TestError.test)
输出结果:
next(😬)
next(😨)
next(😡)
next(🔴)
next(😊)
completed
retry 错误了重试
如果源 Observable 产生一个错误事件,重新对它进行订阅,希望它不会再次产生错误。
retry 操作符将不会将 error 事件,传递给观察者,然而,它会从新订阅源 Observable,给这个 Observable 一个重试的机会,让它有机会不产生 error 事件。retry 总是对观察者发出 next 事件,即便源序列产生了一个 error 事件,所以这样可能会产生重复的元素。
演示:
let disposeBag = DisposeBag()
var count = 1
let sequenceThatErrors = Observable<String>.create { observer in
observer.onNext("🍎")
observer.onNext("🍐")
observer.onNext("🍊")
if count < 5 {
observer.onError(TestError.test)
print("Error encountered")
count += 1
}
observer.onNext("🐶")
observer.onNext("🐱")
observer.onNext("🐭")
observer.onCompleted()
return Disposables.create()
}
sequenceThatErrors
.retry(3)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
🍎
🍐
🍊
Error encountered
🍎
🍐
🍊
Error encountered
🍎
🍐
🍊
Error encountered
Unhandled error happened: test
subscription called from:
.retry(3)表示重复3次,.retry()表示无限重复
timeout 超时就错误
如果源 Observable 在规定时间内没有发出任何元素,就产生一个超时的 error 事件
debug
打印所有的订阅,事件以及销毁信息
演示:
let disposeBag = DisposeBag()
let sequence = Observable<String>.create { observer in
observer.onNext("🍎")
observer.onNext("🍐")
observer.onCompleted()
return Disposables.create()
}
sequence
.debug("Fruit")
.subscribe()
.disposed(by: disposeBag)
输出结果:
2019-12-23 15:42:47.864: Fruit -> subscribed
2019-12-23 15:42:47.872: Fruit -> Event next(🍎)
2019-12-23 15:42:47.872: Fruit -> Event next(🍐)
2019-12-23 15:42:47.872: Fruit -> Event completed
2019-12-23 15:42:47.872: Fruit -> isDisposed
do
当 Observable 的某些事件产生时,你可以使用 do 操作符来注册一些回调操作。这些回调会被单独调用,它们会和 Observable 原本的回调分离。 演示:
let disposeBag = DisposeBag()
Observable.of(1,2,3)
.do(onNext: { (x) in
print("onNext : \(x)")
}, afterNext: { (x) in
print("afterNext : \(x)")
})
.subscribe(onNext:{print($0)})
.disposed(by: disposeBag)
输出:
onNext : 1
1
afterNext : 1
onNext : 2
2
afterNext : 2
onNext : 3
3
afterNext : 3
指定Scheduler
observeOn 在指定Scheduler发元素
指定 Observable 在那个 Scheduler 发出通知。
注意⚠️:一旦产生了 onError 事件, observeOn 操作符将立即转发。他不会等待 onError 之前的事件全部被收到。这意味着 onError 事件可能会跳过一些元素提前发送出去。
subscribeOn 在指定Scheduler执行
指示 Observable 在哪个 Scheduler 发出执行。
评估
reduce 最终结果
reduce 接受一个初始值,和一个操作符号。
reduce 将给定的初始值,与序列里的每个值进行累计运算。得到一个最终结果,并将其作为单个值发送出去。
演示:
let disposeBag = DisposeBag()
Observable.of(10, 100, 1000)
.reduce(1, accumulator: +)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
1111
scan 每个结果
scan 操作符将对第一个元素应用一个函数,将结果作为第一个元素发出。然后,将结果作为参数填入到第二个元素的应用函数中,创建第二个元素。以此类推,直到遍历完全部的元素。
演示:
let disposeBag = DisposeBag()
//.scan(1)提供了一个初始值1
Observable.of(10, 100, 1000)
.scan(1) { aggregateValue, newValue in
aggregateValue + newValue
}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
输出:
11
111
1111
和reduce的区别就在于reduce只发出最终元素
replay
确保观察者接收到同样的序列,即使是在 Observable 发出元素后才订阅。
replay 操作符将 Observable 转换为可被连接的 Observable,并且这个可被连接的 Observable 将缓存最新的 n 个元素。当有新的观察者对它进行订阅时,它就把这些被缓存的元素发送给观察者。
演示:
let intSequence = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
.replay(5)
_ = intSequence
.subscribe(onNext: { print("Subscription 1:, Event: \($0)") })
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
_ = intSequence.connect()
}
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
_ = intSequence
.subscribe(onNext: { print("Subscription 2:, Event: \($0)") })
}
DispatchQueue.main.asyncAfter(deadline: .now() + 8) {
_ = intSequence
.subscribe(onNext: { print("Subscription 3:, Event: \($0)") })
}
输出:
Subscription 1:, Event: 0
Subscription 2:, Event: 0
Subscription 1:, Event: 1
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 3:, Event: 0
Subscription 3:, Event: 1
Subscription 3:, Event: 2
Subscription 3:, Event: 3
Subscription 3:, Event: 4
Subscription 1:, Event: 5
Subscription 2:, Event: 5
Subscription 3:, Event: 5
Subscription 1:, Event: 6
Subscription 2:, Event: 6
Subscription 3:, Event: 6
...
shareReplay
使观察者共享 Observable,观察者会立即收到最新的元素,即使这些元素是在订阅前产生的。
shareReplay 操作符将使得观察者共享源 Observable,并且缓存最新的 n 个元素,将这些元素直接发送给新的观察者。
single
限制 Observable 只有一个元素,否出发出一个 error 事件。
- 如果 Observable 只有一个元素,它将镜像这个 Observable 。
- 如果 Observable 没有元素或者元素数量大于一,它将产生一个 error 事件。
using
创建一个可被清除的资源,它和 Observable 具有相同的寿命
通过使用 using 操作符创建 Observable 时,同时创建一个可被清除的资源,一旦 Observable 终止了,那么这个资源就会被清除掉了。
withLatestFrom
将两个 Observables 最新的元素通过一个函数组合起来,当第一个 Observable 发出一个元素,就将组合后的元素发送出来
- 通过函数组合
- 第一个 Observable才能触发
演示1: 当第一个 Observable 发出一个元素时,就立即取出第二个 Observable 中最新的元素,然后把第二个 Observable 中最新的元素发送出去。
let disposeBag = DisposeBag()
let firstSubject = PublishSubject<String>()
let secondSubject = PublishSubject<String>()
firstSubject
.withLatestFrom(secondSubject)
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
firstSubject.onNext("🅰️")
firstSubject.onNext("🅱️")
secondSubject.onNext("1")
secondSubject.onNext("2")
firstSubject.onNext("🆎")
输出:
2
演示2: 当第一个 Observable 发出一个元素时,就立即取出第二个 Observable 中最新的元素,将第一个 Observable 中最新的元素 first 和第二个 Observable 中最新的元素second组合,然后把组合结果 first+second发送出去。
let disposeBag = DisposeBag()
let firstSubject = PublishSubject<String>()
let secondSubject = PublishSubject<String>()
firstSubject
.withLatestFrom(secondSubject) {
(first, second) in
return first + second
}
.subscribe(onNext: { print($0) })
.disposed(by: disposeBag)
firstSubject.onNext("🅰️")
firstSubject.onNext("🅱️")
secondSubject.onNext("1")
secondSubject.onNext("2")
firstSubject.onNext("🆎")
输出:
🆎2
注意⚠️: 第二个 Observable有元素了,才开始打印