上篇博客我们聊了observe()、map()、filter()延展函数的具体实现方式以及使用方式。我们在之前的博客中已经聊过,Signal的主要功能是位于SignalProtocol的协议延展中的,而且延展函数是非常的多的。今天博客中我们继续来聊SignalProtocol中那些比较核心的延展实现。本篇博客我们就来聊一下take()函数的使用以及实现方式,并且再聊一下Signal中collect()的相关实现。

一、take(first)

本部分我们就来聊一下take(first)的使用方式以及具体的实现方式。与上篇博客的套路类似,我们聊完代码后,依然会给出take(first)函数的运作方式。如果你看过上篇博客的内容的话,那么take(first)方法是比较好理解的。因为take(first)也是可以链式发展的,并且使用时的整体结构与map()和filter()方法差不多,只不过后两者接收的是一个闭包,而take(first)方法接收的是一个值罢了。

1、take(first)方法的使用

下方示例是ReactiveSwift官方给出的take(first)的使用示例,对其解释如下:

  • 首先还是通过pipe()函数来创建一个signal信号量,并获的其内置的observer

  • 然后通过调用signal的take(first)方法来创建一个新的信号量takeSignal。在调用take(first)时,传入的参数是3.

  • 接着创建一个观察者subscriber,并给出该观察者在收到Value事件的处理闭包。

  • 最后就是调用signal内置的observer来发送Value事件了。

从下方代码片段的输出结果我们不难看出,发出的4个Value事件中只有前三个事件会被takeSignal的观察者收到。而其他的takeSignal的观察者是收不到的。从这一点我们就能明确的看出take(first)函数错创建的信号量的功能。take()的参数如果是N的话,那么就表示,take()所返回的信号量只能接受原信号量所发送事件的前N个。

  

2、take(first)方法的具体实现

看完take(first)方法的使用方式,接下来我们就来看一下take(first)的具体代码实现。下方的SignalProtocol的延展就是take(first)方法的实现,解释如下:

  • take()方法也会返回一个新的Signal对象,也是可以链式发展的,不过在创建Signal对象时添加了一些条件判断。

  • 首先必须保证count为非负数的值。

  • 然后当count为0时,直接执行新信号量中observersendCompleted()方法,结束事件的接收。

  • count > 0时,就创建一个take计数变量来记录接收Value事件的次数,如果take == count时,说明接收事件的次数已达到上限。就调用sendCompleted()方法,结束新返回信号量的观察者接收消息。

  

3、执行原理图

take()函数的执行过程与map()filter()函数差不多,都是可以链式发展的。新创建的Signal对象与之前对象间都会有一个桥接观察者。这几个函数间的不同就在于这个桥接观察者在发送消息所遵循的条件不同。下方就是该执行原理图:

二、Collection的使用

接下来我们来看一下接收集合类型的信号量。Signal的collect()相关的方法会生成一个新的信号量,而该信号量可以接受之前信号量的集合。也就是说信号量的值是成批发送的。本部分我们就来聊聊信号量中的集合的使用方式以及具体的代码实现方式。下方是collec相关的延展方法的使用示例。

接下来我们就来一一列举一下集合信号量的使用方式,在ReactiveSwift中,主要有4中集合信号量的使用方式,下面将会一一列举。

1、collect()

下方代码片段就是collect()方法的使用示例,解释如下:

  • 首先调用signal对象的collect()方法生成一个新的信号量collectionSignal

  • 然后给这个集合信号量collectionSignal关联一个观察者subscriber

  • 然后调用原来signal的observer来连续的发送信号量,信号量的值分别为1、2、3、4。最后调用一下sendCompleted()方法表示信号量发送完毕。

  • 最后我们可以看到,collectionSignal的观察者会以集合的形式接收到了上述发送的信号量的值,如下所示。

  

2、collect(count)

collect(count)该方法比上述方法多了一个count参数,该参数表示集合可容纳元素的最大值,当接收消息的个数为count时,那么就将该集合进行输出,并开始下一个集合的积累。下方就是collect(count)的使用方式。

从下方代码片段的输出结果中我们可以看到,输出结果是两个集合,因为集合元素个数的最大值我们设置的为3。所以每个集合最多是3个值。

  

3、collect(_ predicate: @escaping (_ values: [Value]) -> Bool)

该方法接收的是一个条件闭包参数,也就是说predictcate是一个返回Bool类型的条件闭包,闭包中的内容由调用者来提供。该方法可以根据该条件闭包的结果来判断是否将已经收到的信号量的值进行打包发送。下方打包发送的条件是集合中的值的和恰好等于8时才会发送。

  

4、collect(_ predicate: @escaping (_ values: [Value], _ value: Value) -> Bool)

该函数与上述还是类似,也是接收一个条件闭包,只不过给条件闭包的参数除了当前集合内的元素数组外,还有一个当前接收但尚未入集合的信号量的值。我们可以根据这两个参数做一些判断,然后在决定是否进行结合信号量的发送。

下方代码片段的意思是如果当前发送的值为7,那么就将之前的集合进行发送,发送后并清空,然后将当前为7的值加入到清空后的集合中。下方是调用方式以及输出结果。

  

三、Collection相关信号量的实现方式

上面我们看完了collect()及其相关方式的使用示例,接下来我我们就来看以前其内部具体的代码实现了。本部分就来看一下相关的代码实现细节。

1、CollectState<Value>的实现

首先我们先来看一下CollectState的实现。CollectState就是二次封装的数组集合,封装后更适合我们集合信号量进行元素的存储和清空。也就是说,集合信号量所接收的信号量的值,是暂存在CollectState这个泛型集合中的。下方就是CollectState<Value>的实现方式。

该代码比较简单就是对数组进行的二次封装,其中的append(value)方法就负责往数组中添加元素,而flush()方法则负责将数组进行清空。isEmpty计算属性则用来判断values数组是否为空。

  

2、collect(_ predicate: @escaping (_ values: [Value]) -> Bool)方法的实现

接下来我们就来看一下collect(_ predicate: @escaping (_ values: [Value]) -> Bool)方法的实现,该方法中的整体结构与take()以及之前聊的map()、filter()函数相似,都是返回一个新的信号量,并且将这个新的信号量的Observer与之前信号量Bag中的一个Observer对象的事件进行关联。对下方代码片段的解释如下:

  • 首先在创建新的信号量的构造器尾随闭包中创建了一个类型为CollectState<Value>的state,该state集合主要用来暂存原始信号量发送过来的值value。而这个新的信号量的类型为Signal<[Value], Error>类型,也就是说这个新创建的信号量发送的值是一个集合类型。

  • 然后在处理之前信号量发送事件时,将取出来的值append()到state集合中,然后判断predicate()闭包条件的值,如果predicate()条件成立,则集合信号量向其观察者发送state集合,发送后并清除掉state中的元素的值。

  • 当接收到原信号量的sendCompleted()事件时,集合信号量先将stata中的元素发送出去,然后调用其本身的sendCompleted()结束信号量的发送。

  

3、collect(_ predicate: @escaping (_ values: [Value], _ value: Value) -> Bool)

该方法的实现与上述方法的实现极为相识,只不过是闭包条件所携带的参数不同,并且处理条件的方式也不同。由下方代码我们不难看出,当条件闭包成立时,集合信号量进行事件发送,然后将state集合进行情况,然后在将当前的值添加到已经被清空的state集合中。

也就是说,当条件成立时所发送的集合中是不包括当前所接收到的来着原始信号量的值的。具体如下所示:

  

4、collect()和collect(count)的实现

这两个方式的实现就比较简单主要是调用上述方法,给上述方法的条件闭包传入不同的值。因实现方法比较简单,在此就不做过多赘述了。

  

四、collect()工作原理图

上面聊完collect()的具体工作实现,我们再来看一下collect()的工作原理图,因为其代码实现与map()、filter()、take()等方法类似,所以原理图也差不多。下方就是collect()的工作原理图。

从下方的工作原理图我们清楚的可以看到,原信号量Signal发送的是value, collectSignal收到这个value值后,将其暂存到[value]集合中,当predicate()闭包的条件成立时,会调用collectSignal的obser的send(value)方法,将集合[value]发送给collectSignal的观察者。如下所示:

  

今天的博客就先到这儿,下篇博客我们会继续解析ReactiveSwift框架中的其他内容。

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

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #ffffff }
span.s1 { }
span.s2 { color: #de38a5 }
span.s3 { color: #00b1ff }

ReactiveCocoa源码解析(六) SignalProtocol的take(first)与collect()延展实现的更多相关文章

  1. ReactiveSwift源码解析(六) SignalProtocol的take(first)与collect()延展实现

    上篇博客我们聊了observe().map().filter()延展函数的具体实现方式以及使用方式.我们在之前的博客中已经聊过,Signal的主要功能是位于SignalProtocol的协议延展中的, ...

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

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

  3. Celery 源码解析六:Events 的实现

    在 Celery 中,除了远程控制之外,还有一个元素可以让我们对分布式中的任务的状态有所掌控,而且从实际意义上来说,这个元素对 Celery 更为重要,这就是在本文中将要说到的 Event. 在 Ce ...

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

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

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

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

  6. ReactiveCocoa源码解析(二) Bag容器的代码实现

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

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

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

  8. AFNetworking (3.1.0) 源码解析 <六>

    这次继续介绍文件夹Serialization下的类AFURLResponseSerialization.这次介绍就不拆分了,整体来看一下.h和.m文件. 协议AFURLResponseSerializ ...

  9. jQuery 源码解析(六) $.each和$.map的区别

    $.each主要是用来遍历数组或对象的,例如: var arr=[11,12,13,14]; $.each(arr,function(element,index){ //遍历arr数组 console ...

随机推荐

  1. javaWeb学习总结(8)- JSP基础语法(2)

    任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...

  2. JVM、GC与HashMap

    阿里巴巴突然来了个面试邀请电话,问了些java底层的东西,不知所措,所以专门花了些时间做了下学习,顺便记录下,好记性不如烂笔头. 一.对JAVA的垃圾回收机制(GC)的理解 不同于C/C++需要手工释 ...

  3. SmartCoder每日站立会议06

    站立会议内容 讨论了小程序的具体实现方式,主要会加入地图这一元素,使程序看起来更加的方便直观,同时也会使人感到新颖.在对各个点的评论对话功能也在考虑中. 1. 站立会议照片: 2.任务展板 3.燃尽图

  4. VR全景智慧城市,开启“上帝视角”体验‘身临其境’

    VR全景把不同的场景 分为若干个VR视角点 进入一个视角点,用户便能开启"上帝视角" 转动手机,身临其境地360度转动察看,对场景的全貌和细节一目了然.   人生处处有尴尬 比如大 ...

  5. 解密Lazy<T>

    1.Lazy<T>的使用 无意间看到一段代码,在创建对象的时候使用了Lazy,顾名思义Lazy肯定是延迟加载,那么它具体是如何创建对象,什么时候创建对象了? 先看这段示列代码: publi ...

  6. nodeJS之事件events

    前面的话 events模块是node的核心模块,几乎所有常用的node模块都继承了events模块,比如http.fs等.本文将详细介绍nodeJS中的事件机制 EventEmitter 多数 Nod ...

  7. 一起学习java

    一.Servlet学习      下面是Servlet一个整体的继承结构       首先说一下Servlet这个接口这个主要包含的有init,service,destroy等方法,这里主要介绍这3个 ...

  8. redis五种数据类型

    string Redis的字符串和其他编程语言或者其他键值存储提供的字符串非常相似. 命令 行为 GET 获取存储在给定键中的值 SET 设置存储在给定键中的值 DEL 删除存储在给定中的值(这个命令 ...

  9. 关于getHTML()方法和getHtmlAjax()方法 GetHttpLength, 清除HTML标签

    public string getHtml(string Url, string type = "UTF-8") { try { System.Net.WebRequest wRe ...

  10. 配置lnmp

    ===================准备篇: 1.配置防火墙,开启80端口.3306端口vi /etc/sysconfig/iptables-A INPUT -m state –state NEW ...