RxSwift学习——Observable & Observer 既是可监听序列也是观察者

1,335 阅读6分钟

这是我参与8月更文挑战的第6天,活动详情查看:8月更文挑战

声明

出于官方文档的一致性,我还是引用了这个又臭又长的名字——Observable & Observer 既是可监听序列也是观察者。

但是我想说,今天我要讲解的这类型组件用Relay(继电器)这个概念来说明就够了!

另外我没理解RxSwift中频繁使用Subject这个单词,但是我没理解其意义,还望大佬们指点。

前言

上一节,我讲解了Observer(观察者),和之前说明序列比作是工控作业的流水线一样,用于输出。

我把观察者比作是工控中传感器,它用于接收从序列过来的信号,用于输入。

其实在整个工控系统的中,有些传感器不仅接收信号,还需要对信号做转换并输出,这种元件又叫做继电器

理解Relay(继电器)

在我学习Observable&Observer这种类型的时候,看到了BehaviorRelayPublishRelay这两个类,它们是一个相对独立的模块,放在一个叫RxRelay的文件夹中的。

BehaviorRelayPublishRelay分别对应的是BehaviorSubjectPublishSubject这个两种类型,其内部实现都是用BehaviorSubjectPublishSubject的一层封装,具体代码不展开:

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

image.png

继电器(英文名称:relay)是一种电控制器件,是当输入量(激励量)的变化达到规定要求时,在电气输出电路中使被控量发生预定的阶跃变化的一种电器。它具有控制系统(又称输入回路)和被控制系统(又称输出回路)之间的互动关系。通常应用于自动化的控制电路中,它实际上是用小电流去控制大电流运作的一种“自动开关”。故在电路中起着自动调节、安全保护、转换电路等作用。

image.png

注意看这段对Relay的引用中,输出回路输入回路,和Observable(序列)& Observer(观察者) 是不是特别的相似,下图从RxSwift中文文档引用:

image.png

所以我才把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给连上,做加工处理:

image.png

/// 序列构建
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我已经举了例子,其他的都只是举一反三。

  • 中文文档有非常详细的解释与代码例子。

  • 纸上得来终觉浅,自敲自学是正道!

  • 理解了BehaviorSubjectPublishSubjectBehaviorRelayPublishRelay就是通了。

总结

本节我们介绍了一种既是可监听序列也是观察者的RxSwift类型,这里我们叫Relay,我从工控的继电器角度去说明了这种类型的它的使用方式。

通过编写代码以便于大家理解这种可以自产自销,又可以和其他序列绑定然后输出的特殊类型。

至于Relay的类型,我只是简单的摘抄了文档的信息,我个人的建议是先理解其中的一种,然后再逐个攻破,会比我讲解理解的更为深刻。

下一节预告

RxSwift学习这个系列,其实我个人并没明确要写多少篇,不过就目前的篇幅:序列、观察者、继电器三个重要核心类型都已经讲解了。

我个人认为这三个核心类型理解了,其他的只是实战去编码与补遗了。

当然,如果大家对于我这种从工控角度理解的方式喜欢的话,也不妨碍继续,主要是我觉得也没几个人喜欢,😂

下一篇,我打算从RxSwift出发,站在更为宏观的角度看看Rx。

参考文档

Observable & Observer 既是可监听序列也是观察者

RxSwift编写wanandroid客户端现已开源

目前RxSwift编写wanandroid客户端已经开源了——项目链接

我进行了一轮CodeReview,并增加了一些小功能:

  • 添加了iOS的黑暗模式适配

  • 上拉加载更多使用了无感知功能

  • MBProgressHUD替换为SVProgressHUD

记得给个star喔!

附上一张效果图片:

RPReplay_Final1627969241.2021-08-03 13_44_57.gif