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之前,我们要搞清楚,Signal与Observer的关系是一对多的关系,也就是说Signal是广播的形式往Observer发事件的。这也就是典型的“观察者模式”。
一、Signal的简单使用示例
接下来我们先来看一段Signal的使用示例,虽然Single类中有一些创建Signal对象的便利方法,但是下方Demo中我们采用最原始的Signal创建方式,也就是直接调用Signal的构造器。下方的是对该代码段的介绍:
首先我们创建了一个Observer的对象myObserver, 主要是用来给Signal绑定的观察者来发送事件的。
然后我们调用Signal的构造器创建了一个Signal的对象mySignal。通过该构造器的尾随闭包,我们可以拿到这个负责给Single所绑定的所有观察者发送事件的Observer。然后使用myObserver进行存储。
接着我们创建了两个观察者,也就是Observer的对象subscribe01和subscribe02.
创建好观察者后,就是将这两个观察者与我们的mySignal对象进行绑定了。也就是说subscribe01和subscribe02这两个观察者,观察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的类型是RemovalToken,RemovalToken在《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解析
SignalState在Signal中所扮演的角色是比较重要的,因为其中的活跃状态.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,从这个类结构中可以看出Signal与Observer是一对多的关系。
3、TerminatingState类的实现
TerminatingState类的实现与AliveState类的实现差不多,下方是TerminatingState类的代码,在该代码实现中也有一个存储着Observer对象的Bag容器。该Bag容器中存储的是该状态下所对应的Observer,而下方的Event类型的event属性则是该状态所对应的事件。如下所示:
今天博客就先到这儿,下篇博客我们继续对ReactiveSwift中的Signal的实现进行介绍。
上述代码github分享地址:https://github.com/lizelu/TipSwiftForRac
ReactiveSwift源码解析(三) Signal代码的基本实现的更多相关文章
- ReactiveCocoa源码解析(三) Signal代码的基本实现
上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...
- ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现
本篇博客我们就来聊一下combineLatest()的使用以及具体的实现方式.在之前的<iOS开发之ReactiveCocoa下的MVVM>的博客中我们已经聊过combineLatest( ...
- ReactiveSwift源码解析(十) Lifetime代码实现
为了之后博客的进行,本篇博客我们就来聊一下ReactiveSwift框架中的Lifetime类的具体实现.从Lifetime这个名字中我们就这道,就是生命周期.在ReactiveSwift中使用Lif ...
- ReactiveSwift源码解析(四) Signal中的静态属性静态方法以及面向协议扩展
上篇博客我们聊了Signal的几种状态.Signal与Observer的关联方式以及Signal是如何向关联的Observer发送事件的.本篇博客继续上篇博客的内容,来聊一下Signal类中静态的ne ...
- ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现
上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...
- Celery 源码解析三: Task 对象的实现
Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...
- Mybatis源码解析(三) —— Mapper代理类的生成
Mybatis源码解析(三) -- Mapper代理类的生成 在本系列第一篇文章已经讲述过在Mybatis-Spring项目中,是通过 MapperFactoryBean 的 getObject( ...
- ReactiveSwift源码解析(一) Event与Observer代码实现
ReactiveCocoa这个框架是做什么用的本篇博客就不做过多赘述了,什么是"响应式编程"也不多聊了,自行Google吧.本篇博客的主题是解析ReactiveCocoa框架中的核 ...
- ReactiveSwift源码解析(二) Bag容器的代码实现
今天博客我接着上篇博客的内容来,上篇博客我们详细的看了ReactiveSwift中的Observer已经Event的代码实现.接下来我们来看一下ReactiveSwift中的结构体Bag的实现.Bag ...
随机推荐
- 使用SQL命令批量替换WordPress站点中图片的URL链接地址
本文由荒原之梦原创,原文链接:http://zhaokaifeng.com/?p=689 前言: 本文记录了使用SQL命令批量替换URL的方法以及除了替换URL之外,网站更换图片URL地址所必须的其他 ...
- 系列博文-Three.js入门指南(张雯莉)-网格 setInterval方法 requestAnimationFrame方法 使用stat.js记录FPS
第6章 动画 在本章之前,所有画面都是静止的,本章将介绍如果使用Three.js进行动态画面的渲染.此外,将会介绍一个Three.js作者写的另外一个库,用来观测每秒帧数(FPS). CSS3动画那么 ...
- Sublime Text 3 Build 3065 License key 注册码 秘钥
-– BEGIN LICENSE -– Andrew Weber Single User License EA7E-855605 813A03DD 5E4AD9E6 6C0EEB94 BC99798F ...
- 利用pytesser识别图形验证码
简单识别 1.一般思路 验证码识别的一般思路为: 图片降噪 图片切割 图像文本输出 1.1 图片降噪 所谓降噪就是把不需要的信息通通去除,比如背景,干扰线,干扰像素等等,只剩下需要识别的文字,让图片变 ...
- 【BZOJ 2713】[Violet 2]愚蠢的副官&&【BZOJ1183】[Croatian2008]Umnozak——【数位DP】
题目链接: 2713传送门 1183传送! 题解: 由于看不懂英文题解(十个单词十一个不认识……),所以只能自己想QAQ. 其实乱搞就好= =. 首先我们发现,各位数字乘积要在1e9以下才可能有用,这 ...
- python 库位置
l\\Programs\\Python\\Python36\\lib 默认库安装路径 \\Programs\\Python\\Python36\\lib\\site-packages 第三方库安装 ...
- 一个优秀团队leader应该具备的几点素质
首先,技术要过硬.毕竟一个团队是在靠技术为别人创造价值的,一定程度上,团队leader的技术能力决定了整个团队的技术上限.leader对技术的坚持和追求很可能会影响团队成员对技术的坚持和追求,至少le ...
- Windows上安装配置SSH教程(7)——几种方式对比
服务端:Windows XP 客户端:Windows 10 由于Cygwin也可以安装OpenSSH,所以客户端其实可以直接使用Cygwin安装OpenSSH,那么在Windows下使用SCP(安全拷 ...
- java泛型中使用的排序算法——归并排序及分析
一.引言 我们知道,java中泛型排序使用归并排序或TimSort.归并排序以O(NlogN)最坏时间运行,下面我们分析归并排序过程及分析证明时间复杂度:也会简述为什么java选择归并排序作为泛型的排 ...
- Java基础系列之你真的懂==与equals的区别吗?
对于Java初学者而言,可能会对这两个比较方法比较模糊,有的人可能会觉得两个的方法使用起来结果是一样的等.如果你有这样的想法,我建议你来看看这边博客,让你充分了解这两个比较的异同,以及他们底层是如何比 ...