这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战
声明
出于官方文档的一致性,我还是引用了这个又臭又长的名字——Observable & Observer 既是可监听序列也是观察者。
但是我想说,今天我要讲解的这类型组件用Relay(继电器)
这个概念来说明就够了!
另外我没理解RxSwift中频繁使用Subject这个单词,但是我没理解其意义,还望大佬们指点。
前言
上一节,我讲解了Observer(观察者),和之前说明序列
比作是工控作业的流水线一样,用于输出。
我把观察者
比作是工控中传感器,它用于接收从序列过来的信号,用于输入。
其实在整个工控系统的中,有些传感器不仅接收信号,还需要对信号做转换并输出,这种元件又叫做继电器。
理解Relay(继电器)
在我学习Observable&Observer这种类型的时候,看到了BehaviorRelay
和PublishRelay
这两个类,它们是一个相对独立的模块,放在一个叫RxRelay
的文件夹中的。
BehaviorRelay
和PublishRelay
分别对应的是BehaviorSubject
和PublishSubject
这个两种类型,其内部实现都是用BehaviorSubject
和PublishSubject
的一层封装,具体代码不展开:
public final class BehaviorRelay<Element>: ObservableType {
private let _subject: BehaviorSubject<Element>
/// Accepts `event` and emits it to subscribers
public func accept(_ event: Element) {
self._subject.onNext(event)
}
.
.
.
public final class PublishRelay<Element>: ObservableType {
private let _subject: PublishSubject<Element>
// Accepts `event` and emits it to subscribers
public func accept(_ event: Element) {
self._subject.onNext(event)
}
·
·
·
真正让我感兴趣的是这个单词Relay:
继电器(英文名称:relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。故在电路中起着自动调节、安全保护、转换电路等作用。
注意看这段对Relay的引用中,输出回路与输入回路,和Observable(序列)& Observer(观察者) 是不是特别的相似,下图从RxSwift中文文档引用:
所以我才把RxSwift中的具有这种特性的类型叫做继电器
。
正是从Relay为起点,让我联想到工控(真的得感谢做工控编程那几年的经历),再从工控的角度看RxSwift,整个世界豁然开朗。
既可以作为输入又可以作为输出的组件,这就是RxSwift中所谓的Observable & Observer。
使用Relay
从上面的理解中我们可以知道,在RxSwift中,Relay(继电器)它既可以产生序列,又可以作为观察者去消费序列。
- 可以自产自销:
/// 定义一个继电器
let subject = PublishSubject<Int>()
/// 消费生产的序列
subject.subscribe { (event: Event<Int>) in
switch event {
case .next(let some):
print(some)
case .error(let error):
print(error)
case .completed:
print(event.debugDescription)
}
}.disposed(by: disposeBag)
/// 自己生产序列
subject.onNext(0)
subject.onNext(1)
subject.onNext(2)
subject.onNext(3)
subject.onNext(4)
subject.onNext(5)
打印日志如下:
0
1
2
3
4
5
completed
- 可以找一个序列,然后把Relay给连上,做加工处理:
/// 序列构建
let observable = Observable.from([0, 1, 2, 3, 4, 5])
/// 定义一个继电器
let subject = PublishSubject<Int>()
/// 序列与继电器连接
observable.bind(to: subject)
/// 消费生产的序列
subject.subscribe { (event: Event<Int>) in
switch event {
case .next(let some):
/// 注意这里做了加工,即some + some
print(some + some)
case .error(let error):
print(error)
case .completed:
print(event.debugDescription)
}
}.disposed(by: disposeBag)
/// 中继继电器加工后输出:
observable.bind(to: subject)
打印日志如下:
0
2
4
6
8
10
completed
注意事项
不管是Relay自产自销,还是通过其他Observable绑定到Relay,我们都是先subscribe
订阅,然后再使用onNext
产生序列或再使用bind(to:)函数
,完全是因为PublishSubject
这个继电器本身的特性决定的:
PublishSubject 将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者。
通过对于继电器的选型,来达到不同的效果。实际上与工控的设计中对继电器的选型一致。
AsyncSubject、PublishSubject、ReplaySubject、BehaviorSubject、ControlProperty
诚如上一节Observer有两个类型:AnyObserver和Binder一样。
Relay也有比较常用的五种类型:AsyncSubject、PublishSubject、ReplaySubject、BehaviorSubject、ControlProperty。
这里我简略的摘抄出中文文档对于这几种Relay的区别。
AsyncSubject 将在源
Observable
产生完成事件后,发出最后一个元素(仅仅只有最后一个元素),如果源Observable
没有发出任何元素,只有一个完成事件。
PublishSubject 将对观察者发送订阅后产生的元素,而在订阅前发出的元素将不会发送给观察者。如果你希望观察者接收到所有的元素,你可以通过使用
Observable
的create
方法来创建Observable
,或者使用 ReplaySubject。
ReplaySubject 将对观察者发送全部的元素,无论观察者是何时进行订阅的。
当观察者对 BehaviorSubject 进行订阅时,它会将源
Observable
中最新的元素发送出来(如果不存在最新的元素,就发出默认元素)。然后将随后产生的元素发送出来。
ControlProperty 专门用于描述 UI 控件属性的。
注意事项
我为何不细讲所有的Relay类型?主要有以下几个原因:
-
PublishSubject我已经举了例子,其他的都只是举一反三。
-
中文文档有非常详细的解释与代码例子。
-
纸上得来终觉浅,自敲自学是正道!
-
理解了
BehaviorSubject
和PublishSubject
,BehaviorRelay
和PublishRelay
就是通了。
总结
本节我们介绍了一种既是可监听序列也是观察者的RxSwift类型,这里我们叫Relay,我从工控的继电器角度去说明了这种类型的它的使用方式。
通过编写代码以便于大家理解这种可以自产自销,又可以和其他序列绑定然后输出的特殊类型。
至于Relay的类型,我只是简单的摘抄了文档的信息,我个人的建议是先理解其中的一种,然后再逐个攻破,会比我讲解理解的更为深刻。
下一节预告
RxSwift学习这个系列,其实我个人并没明确要写多少篇,不过就目前的篇幅:序列、观察者、继电器三个重要核心类型都已经讲解了。
我个人认为这三个核心类型理解了,其他的只是实战去编码与补遗了。
当然,如果大家对于我这种从工控角度理解的方式喜欢的话,也不妨碍继续,主要是我觉得也没几个人喜欢,😂
下一篇,我打算从RxSwift出发,站在更为宏观的角度看看Rx。
参考文档
Observable & Observer 既是可监听序列也是观察者
RxSwift编写wanandroid客户端现已开源
目前RxSwift编写wanandroid客户端已经开源了——项目链接。
我进行了一轮CodeReview,并增加了一些小功能:
-
添加了iOS的黑暗模式适配
-
上拉加载更多使用了无感知功能
-
MBProgressHUD替换为SVProgressHUD
记得给个star喔!
附上一张效果图片: