ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现
本篇博客我们就来聊一下combineLatest()的使用以及具体的实现方式。在之前的《iOS开发之ReactiveCocoa下的MVVM》的博客中我们已经聊过combineLatest()的用法,虽然是使用老版本的ReactiveCocoa和Objective-C语言介绍的,不过使用原理上都是一致的。都是将两个信号量进行合并,当其中一个信号量发出Value事件时,如果另一个信号量之前也发送过Value事件,那么就取出最后一个事件的Value值与当前发送的事件值进行合并,然后将合并后的值发送给新的信号量的观察者。如果其中一个未发送过任何Value,那么将不会向合并后的信号量的观察者发送事件。下方会进行详细的叙述。
下面我们就来仔细的聊一下combineLatest()的使用方式、具体的代码实现以及合并信号量的工作原理。下方的使用示例我们还是与《iOS开发之ReactiveCocoa下的MVVM》这篇博客中聊combineLatest()时使用是示例相同,只不过我们是使用的Swift语言写的,详情如下。
一、combineLatest()使用
下方代码片段是combineLatest()使用方式,介绍如下:
首先创建两个信号量,一个是signalString,用来发送Value值为String类型的信号。另一个是signalInt,用来发送Value值为Int类型的信号。
调用信号量signalString的combineLatest()方法,将signalString信号量最后发送的值与信号量signalInt最后发送的值进行合并。然后将合并后的元组(String, Int)发送给新创建的combineLatestSignal信号量的所有观察者。
接着就是调用signalString和signalInt所对应的observer对象来发送Value事件了。
从输出结果我们不难看出,无论是signalString信号量还是signalInt信号量发出的Value消息,只要是另一个信号量的LastValue不为nil。那么新的信号量combineSignal的观察者就会收到相应的合并后的值,如下具体结果如下所示:
针对上述的示例,我们画了下方的简图来说明合并信号量的工作方式。Letters和Number是两个信号量,Combine是两者通过combineLatest()方法生成的新的信号量,然后Letters和Number信号量就随机发送消息。Combine信号量根据Letter和Numbers发送值的情况进行信号量的输出。具体如下所示。
二、combineLatest()的具体代码实现
接下来我们就来看一下combineLatest()代码的具体实现。下方就是该方法对应的核心代码:
首先下方这个泛型函数的参数是一个信号量,而返回值是一个新的信号量,而这个新的信号量的类型是一个可以接受元组的信号量。而这个元组中的两个值就是这两个信号量最后一个值合并而成的。
其次创建了一个NSLock类型的锁,用来保证多线程下的原子性操作。
定义声明两个常量对象,用来存储两个合并信号量最后发送的值。CombineLatestState<Value>类的实现是比较简单的,目的就是为了暂存信号量最后发出的值。
然后有定义了一个无参闭包onBothValue, 而这个闭包体中所做的事情是像新生成的合并信号量发送合并后的元组消息。这样,与新信号量所关联的观察者Observer就会收到这个元组。
紧接着就是创建了一个新的代理观察者observerDelegate, 用来代理新信号量的Observer来发送各种事件。而这个observerDelegate代理观察者是代替合并后的新信号量发送事件的。
最后要做的就是将observerDelegate与要合并的两个信号量进行整合关联,使得要合并的两个信号量中的任何一个信号量发出事件时。在两者都有LatestValue的情况下,这个新合并的信号量所绑定的观察者都可以接收到该事件。
具体代码如下所示:
下方这个方法就负责将新的信号量的发送事件的Observer与之前信号量进行整合。具体做法就是往之前的信号量的Bag容器中添加一个新的观察者Observer,在这个新的观察者处理Event事件时,调用ObserverDelegate的相关事件即可。
在上述代码中,我们对暂存之前两个信号量最后发出的值的signalState和otherState进行了相关信息的打印。先打印了hashValue,然后打印了其暂存的值。当着两个对象中的latestValue皆不为空时,那么就调用observerDelegate的sendValue方法执行onBothValue闭包,向合并信号量所有的Observer发送元组消息即可。
下方就是对signalState和otherState的相关信息进行的打印 ,从打印信息中我们可以看出,尽管在observerWithState()函数中是以参数的形式获取的signalState和otherState,但是其内存地址是不变的,独一份。而且当这两个都有lastestValue的情况下,合并信号量的观察者才会收到相应的Value事件。具体如下所示。
三、Latest合并原理图
针对上述的代码实现,以及参考之前博客中原理图的形式,于是乎我们给出了下方的这个原理图。原理图应该是清晰明了,一目了然的,在此就不做过多的赘述了。通过下图的结构,我们不难看出,combineLatestSignal信号量仍然是可以进行链式发展的。
在Signal.swift文件中关于SignalProtocol的扩展的方法中,基本上是按照上述的套路来扩展的。大体就是一个方法返回一个新的信号量,这个新的信号量与原始信号量间通过桥接信号量来进行关联。不同的方法在处理原信号量往新的信号量发送事件时,在中间所做的事情不同。Signal.swift文件中还有好多类似的方法,在此就不一一进行介绍了,如果你对某个方法的实现感兴趣,可以采用上述的套路来进行解析。
今天的博客就先到这儿,下篇博客我们会继续解析ReactiveSwift框架中的其他内容。
上述代码github分享地址:https://github.com/lizelu/TipSwiftForRac。
ReactiveSwift源码解析(七) Signal的CombineLatest的代码实现的更多相关文章
- ReactiveSwift源码解析(三) Signal代码的基本实现
上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...
- ReactiveSwift源码解析(四) Signal中的静态属性静态方法以及面向协议扩展
上篇博客我们聊了Signal的几种状态.Signal与Observer的关联方式以及Signal是如何向关联的Observer发送事件的.本篇博客继续上篇博客的内容,来聊一下Signal类中静态的ne ...
- ReactiveCocoa源码解析(三) Signal代码的基本实现
上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...
- ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现
上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...
- ReactiveSwift源码解析(一) Event与Observer代码实现
ReactiveCocoa这个框架是做什么用的本篇博客就不做过多赘述了,什么是"响应式编程"也不多聊了,自行Google吧.本篇博客的主题是解析ReactiveCocoa框架中的核 ...
- ReactiveSwift源码解析(二) Bag容器的代码实现
今天博客我接着上篇博客的内容来,上篇博客我们详细的看了ReactiveSwift中的Observer已经Event的代码实现.接下来我们来看一下ReactiveSwift中的结构体Bag的实现.Bag ...
- QT源码解析(七)Qt创建窗体的过程,作者“ tingsking18 ”(真正的创建QPushButton是在show()方法中,show()方法又调用了setVisible方法)
前言:分析Qt的代码也有一段时间了,以前在进行QT源码解析的时候总是使用ue,一个函数名在QTDIR/src目录下反复的查找,然后分析函数之间的调用关系,效率实在是太低了,最近总结出一个更简便的方法, ...
- Celery 源码解析七:Worker 之间的交互
前面对于 Celery 的分布式处理已经做了一些介绍,例如第五章的 远程控制 和第六章的 Event机制,但是,我认为这些分布式都比较简单,并没有体现出多实例之间的协同作用,所以,今天就来点更加复杂的 ...
- jQuery 源码解析(七) jQuery对象和DOM对象的互相转换
jQuery对象是一个类数组对象,它保存的是对应的DOM的引用,我们可以直接用[]获取某个索引内的DOM节点,也可以用get方法获取某个索引内的DOM节点,还可以用toArray()方法把jQuery ...
随机推荐
- 在wamp下使用netbeans开启Xdbug
1.到http://www.xdebug.org 下载与PHP对应的xdebug版本,也可以把phpinfo源码粘贴到http://www.xdebug.org/find-binary.php,提交后 ...
- HTML中部分标签的嵌套问题
书写HTML结构的时候,对于标签的嵌套问题,在我发现这个问题之前,都不在自己的考虑之中,还傻傻的以为标签之间是可以进行百搭的! 其实,有些标签是不能进行随意嵌套,如果你没有深受其害,你是不会发现它的存 ...
- python——爬虫&问题解决&思考(1)
最近刚接触python,找点小任务来练练手,希望自己在实践中不断的锻炼自己解决问题的能力.这个小爬虫来自慕课网的一门课程,我在这里记录的是自己学习的过程中遇到的问题和解决方法以及爬虫之外的思考. 这次 ...
- 源代码安装软件-MySQL
一.源码安装 1.经典的源代码安装三步曲: 1.编译前的配置 ./configure 2.编译 make 3.安装 make install 2.源代码软件安装步骤: 1.下载软件包 2.校验软件包 ...
- APUE-文件和目录(三)函数chown 和lchown
下面的几个chown函数可用于更改文件的用户ID和组ID.如果两个参数owner或group中的任意一个是-1,则对应的ID不变. #include<unistd.h> int chown ...
- jquery不兼容input的change事件处理
因为客户使用系统一般都是用IE版本的浏览器,所以每次在chrome下调试之后都要在IE走一遍; 这次准备在选择开始时间或者结束时间之后在下方能及时给出对应的天数,但是在IE8下试了change时间根本 ...
- ASP.NET MVC5(四):数据注解和验证
前言 用户输入验证的工作,不仅要在客户端浏览器中执行,还要在服务端执行.主要原因是客户端验证会对输入数据给出即时反馈,提高用户体验:服务器端验证,主要是因为不能完全信任用户提供的数据.ASP.NET ...
- maven项目转成web项目没有生成WebContent目录
有时候建立maven项目转成web项目没有生成WebContent目录,此时把Dynamic web module 去掉勾选,然后ok,再点开项目的properties,再选中Dynamic web ...
- 转化来的图标用法symbol引用‘font-class引用及Unicode引用
- 短信发送接口被恶意访问的网络攻击事件(三)定位恶意IP的日志分析脚本
前言 承接前文<短信发送接口被恶意访问的网络攻击事件(二)肉搏战-阻止恶意请求>,文中有讲到一个定位非法IP的shell脚本,现在就来公布一下吧,并没有什么技术难度,只是当时花了些时间去写 ...