• ReactiveSwift源码解析(三) Signal代码的基本实现


    上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见《ReactiveSwift源码解析之Bag容器》。本篇博客我们就来聊一下信号量,也就是Signal的的几种状态以及Signal的基本实现。当然本篇博客所解析的源码会用到上篇博客介绍的Bag容器。本篇博客我们先通过一个示例来看一下Signal是如何工作的,具体说来就是Signal是如何与Observer关联的,来聊一下Observer是如何观察和Signal发出的信号的。

    之前我们也详细的聊过Observer和Event相关的东西,详情请参见《ReactiveSwift源码解析之Event与Observer》。本篇博客我们先通过一个实例来看一下Signal和Observer的关系,然后在看一下Signal中的几种状态,最后看一下Signal是如何给Observer发送事件(通知)的。

    在聊Signal之前,我们要搞清楚,SignalObserver的关系是一对多的关系,也就是说Signal是广播的形式往Observer发事件的。这也就是典型的“观察者模式”。

    一、Signal的简单使用示例

    接下来我们先来看一段Signal的使用示例,虽然Single类中有一些创建Signal对象的便利方法,但是下方Demo中我们采用最原始的Signal创建方式,也就是直接调用Signal的构造器。下方的是对该代码段的介绍:

    • 首先我们创建了一个Observer的对象myObserver, 主要是用来给Signal绑定的观察者来发送事件的。
    • 然后我们调用Signal的构造器创建了一个Signal的对象mySignal。通过该构造器的尾随闭包,我们可以拿到这个负责给Single所绑定的所有观察者发送事件的Observer。然后使用myObserver进行存储。
    • 接着我们创建了两个观察者,也就是Observer的对象subscribe01subscribe02.
    • 创建好观察者后,就是将这两个观察者与我们的mySignal对象进行绑定了。也就是说subscribe01subscribe02这两个观察者,观察mySignal发过来的事件。
    • 最后就是调用mySignal中的myObserver进行事件的发送了。

      

    从上述示例的输出结果,我们可以看出,当myObserver发送Value事件时,mySignal的所有Value事件的观察者都可以收到该事件。接下来我我们就来剖析一下Signal与Observer是如何进行绑定的。以及Signal是如何发送事件的。

    下面我们可以通过一个图来简单的看一下Signal和Observer的关系。下方画了一个简图来表示这一关系。左边是我们创建的多个Observer对象,然后我们可以将这些对象与Signal对象进行关联,这个关联本质上是将其存放在Signal对象中的Bag中。在Signal对象中也有一个observer对象。Signal的用户可以通过Signal构造函数的尾随闭包来获取到这个内置的observer对象,也即是上述示例的myObserver,使用这个myObserver对象给Bag中所有的Observer发送相应的事件。

    在myObserver发送事件的方法中,本质上是对Bag中所有元素的遍历,将myObserver所接受的事件转发给Bag中所有的元素。接下来我们要做的事情就是看其具体的实现方式,当然,具体实现是比下方这张简图的结构要复杂一些。

      

    二、Signal的构造器与observer(observer: Observer)方法

    顺藤摸瓜、我们可以从上述实例为切入点来展开对Single实现的解析。在上述实例中我们使用到了Observer,在之前的博客中我们对Observer以及Observer所发送事件Event进行详细的介绍,所以就不对其进行过多赘述了。接下来我们就把重点放在Signal上。

    1、Signal的构造器

    上述示例初次用到Signal时,是使用的Signal的构造器,接下来我们就来看一下Signal的构造器的实现。下方代码段就是Signal类中的核心属性以及构造方法了。在构造器中我们可以看出是对这些属性进行了初始化。SignalState来标记当前信号量的状态,在Signal中扮演的角色还是比较重要的,稍后会进行介绍。两个NSLock的常量就是两个同步锁,保证原子性操作。

    最下方就是初始化了一个Observer的常量,这个常量就负责给Signal所绑定的观察者进行发送事件,通过构造器的尾随闭包回调给Signal的使用这。该observer常量对应这上述实例的myObserver。observer在初始化时,直接调用的是Observer的构造器,尾随闭包就是Observer中Action的闭包体。

      

    2、添加观察者的方法:observer(observer: Observer)

    接下来我们在来看示例中添加观察者使用到的observer(observer: Observer)方法。下方就是observer()方法的具体实现。

    • 首先我们来看一下token,token的类型是RemovalTokenRemovalToken在《ReactiveSwift源码解析之Bag容器》中详细的介绍过。主要是用来移除Bag容器中元素的。
    • 然后判断当前的Signal是否是SignalState.alive状态,如果是的话,取出SignalState.alive状态所绑定的值snapshot。此处的snapshot就是一个Bag的对象,用来存储与Signal所关联的所有Observer。然后就是snapshot这个Bag中添加关联的Observer了,关联后,就是更新SignalState.alive所关联的值了。当然为了保证状态更新的原子性操作,这里使用了updateLock
    • 下方负责初始化Disposable对象,该对象用来将Signal对应的Observer置为失效的状态。本质上就是移除观察者的操作。ActionDisposable中主要做的事情就是从Bag中根据Token移除Observer对象。

      

    3、myObserver.send(value)方法

    接下来我们就来看一下在我们实例中myObserver.send(value)方法所做的事情。也就是Signal构造器中对observer对象赋值是尾随闭包中要做的事情。下方就是send(value)方法主要做的事情,如果Signal是活跃状态的话,就会取出该状态值所绑定的Bag对象,Bag中存储的是所有和Signal所关联的Observer,然后遍历Bag中所有的Observer对象,并调用Observer对的Action闭包执行相应的事件。具体做法如下:

      

     

    三、SignalState解析

    SignalStateSignal中所扮演的角色是比较重要的,因为其中的活跃状态.alive就关联着存储所有可以接受信号量事件的观察着的Bag,稍后会进行解析。本部分我们就来详细的看一下SignalState中的内容实现。

    1、SignalState枚举的实现

    SignalState的代码实现就比较简单了,就是一个枚举。而这个枚举中有三个枚举值,这三个枚举值对应这信号量的三种状态。

    • alive状态表示信号量处于活跃状态,可以发送事件,alive状态有一个AliveState类型的关联值,稍后会对AliveState进行介绍。
    • terminating则说明信号量正在被终止,terminating也有一个关联值,该关联值是一个TerminatingState类型的值,下方也会介绍到。
    • terminated状态说明该信号量处于终止状态,不可在发事件了。

      

    2、AliveState类的实现

    下方就是AliveState类的具体实现,AliveState类的主要作用就是与SignalState.alive状态进行关联的。在AliveState中我们可以看到有一个observers的属性,该属性就是Bag容器,其中可存储的类型是Observer。也就是说,在信号量活跃状态下所绑定的观察者都存储在这个Bag中。而retaining属性中存储的就是与Bag中观察者所对应的Signal,从这个类结构中可以看出SignalObserver是一对多的关系。

      

     

    3、TerminatingState类的实现

    TerminatingState类的实现与AliveState类的实现差不多,下方是TerminatingState类的代码,在该代码实现中也有一个存储着Observer对象的Bag容器。该Bag容器中存储的是该状态下所对应的Observer,而下方的Event类型的event属性则是该状态所对应的事件。如下所示:

      

    今天博客就先到这儿,下篇博客我们继续对ReactiveSwift中的Signal的实现进行介绍。

    上述代码github分享地址:https://github.com/lizelu/TipSwiftForRac  

  • 相关阅读:
    jQuery Ajax学习
    jquery 学习
    jquery after append appendTo三个函数的区别
    rtmp服务器以及rtmp推流/拉流/转发
    Python字符编码详解
    Python自省(反射)指南
    Python线程指南
    Python正则表达式指南[转载]
    Python2.7 threading模块学习
    python中if __name__ == '__main__': 的解析
  • 原文地址:https://www.cnblogs.com/ludashi/p/6946194.html
Copyright © 2020-2023  润新知