上篇博客我们详细的聊了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

ReactiveSwift源码解析(三) Signal代码的基本实现的更多相关文章

  1. ReactiveCocoa源码解析(三) Signal代码的基本实现

    上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...

  2. ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现

    本篇博客我们就来聊一下combineLatest()的使用以及具体的实现方式.在之前的<iOS开发之ReactiveCocoa下的MVVM>的博客中我们已经聊过combineLatest( ...

  3. ReactiveSwift源码解析(十) Lifetime代码实现

    为了之后博客的进行,本篇博客我们就来聊一下ReactiveSwift框架中的Lifetime类的具体实现.从Lifetime这个名字中我们就这道,就是生命周期.在ReactiveSwift中使用Lif ...

  4. ReactiveSwift源码解析(四) Signal中的静态属性静态方法以及面向协议扩展

    上篇博客我们聊了Signal的几种状态.Signal与Observer的关联方式以及Signal是如何向关联的Observer发送事件的.本篇博客继续上篇博客的内容,来聊一下Signal类中静态的ne ...

  5. ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现

    上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...

  6. Celery 源码解析三: Task 对象的实现

    Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...

  7. Mybatis源码解析(三) —— Mapper代理类的生成

    Mybatis源码解析(三) -- Mapper代理类的生成   在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...

  8. ReactiveSwift源码解析(一) Event与Observer代码实现

    ReactiveCocoa这个框架是做什么用的本篇博客就不做过多赘述了,什么是"响应式编程"也不多聊了,自行Google吧.本篇博客的主题是解析ReactiveCocoa框架中的核 ...

  9. ReactiveSwift源码解析(二) Bag容器的代码实现

    今天博客我接着上篇博客的内容来,上篇博客我们详细的看了ReactiveSwift中的Observer已经Event的代码实现.接下来我们来看一下ReactiveSwift中的结构体Bag的实现.Bag ...

随机推荐

  1. Lsyncd - 实时文件同步工具(精译)

    原文: http://axkibe.github.io/lsyncd/ 描述 Lsyncd监视本地目录树事件监视器接口(inotify或fsevents).它聚集并组合事件几秒钟,然后生成一个(或多个 ...

  2. Linux时间子系统之四:Timer在用户和内核空间流程

    用户空间应用中创建一个Timer(alarm/setitimer/POSIX Timer等等),然后程序继续执行: 内核进入创建/设置Timer系统调用,开始计时,在超时后通过何种方式通知用户空间: ...

  3. 远程备份binlog服务

    Ⅰ.bonlog server介绍 对于binlog的备份,之前文章里说的是有从机,一般不备份,那现在人家就是 要备份嘛,怎么办嘛, 写个脚本每天夜里去把前一天产生的binlog拷贝出来可以不? 行啊 ...

  4. javascript 事件编程之事件(流,处理,对象,类型)

    1. 事件处理 1.1. 绑定事件方式 1)行内绑定 语法: //最常用的使用方式 <元素 事件="事件处理程序"> 2)动态绑定 //结构+样式+行为分离的页面(ht ...

  5. DW自动换行

    查看→代码视图选项→自动换行

  6. IntelliJ IDEA(十) :常用操作

    IDEA功能详细,快捷键繁多,但是实际开发时不是所有都能用上,如果我们熟悉一些常用的也足够满足我们日常开发了,多的也只是提高我们的B格. 1.自定义主题 IDEA默认的主题有三款,分别是Intelli ...

  7. bzoj2281 [Sdoi2011]黑白棋

    一眼$nimk$游戏,后来觉得不对劲,看了黄学长博客发现真的不是$nimk$. 就当是$nimk$做吧,那么我们要保证每一位上一的个数都是$d+1$的倍数. $dp$:$f[i][j]$表示从低到高第 ...

  8. ArcGIS API for JavaScript 入门教程[1] 渊源

    ->对于萌新,你可能需要了解一下这个东西是什么 ->对于已经知道要用这个东西的开发者,你可能需要了解一下它的底层机制 不针对大牛.龟速更新ing. 转载注明出处.博客园&CSDN& ...

  9. Leetcode解题思路总结(Easy篇)

    终于刷完了leetcode的前250道题的easy篇.好吧,其实也就60多道题,但是其中的套路还是值得被记录的. 至于全部code,请移步github,题目大部分采用python3,小部分使用C,如有 ...

  10. Charles 连接手机抓包出现Unknown,一直无法抓包的问题解决

    mac电脑安装了charles并且确保已经安装成功,https抓包需要安装的相关的证书已经安装,并且手机浏览器中输入chls.pro/ssl已经将证书下载完成,但是手机与电脑相连通过点击手机应用还是无 ...