上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于《Signal中的静态属性静态方法以及面向协议扩展》。并且聊了Signal的所有的g功能扩展都是放在Signal所实现的SignalProtocol协议的扩展中的。本篇博客就沿袭上篇博客的内容,我们来聊一下SignalProtocol的部分扩展。本篇博客我们主要来聊一下对Signal添加Observer的observe()方法扩展的具体实现,并且聊一下Signal的MapFilter相关的功能扩展的具体实现。

当然我们在聊相关源码的具体实现时,会给出相关的测试用例,然后再根据测试用例来理解其代码实现。

一、observe()方法的扩展

首先我们来看一下observe()方法的扩展。通过前几篇博客的介绍,我们知道SiganlObserver之间的关联是通过observe()方法来实现的。而observe()方法的核心实现在上篇博客中已经进行了详细介绍。而在协议扩展中又对observe()方法进行了一些扩展,这些扩展主要是针对一些特定功能为observe()的使用方式添加快捷调用方式。

1、observe()方法扩展的具体实现

下方个SignalProtocol的延展主要是对observe()方法的扩展,在每个扩展方法中最后还是得调用Signal类中所实现的observe()方法。还是那句话,下方的这些observe()方法的扩展主要还是Signal类中observe()方法的快捷方式。下方将对observe()的每个快捷方法进行介绍。

  • observe(action) : 该方法传入的是一个Action闭包,该Action闭包其实就是Observer类中的Action闭包。也就是在调用observe(action)方法时,为Observer的Action提供了闭包体。而在observe(action)方法中要做的就是实例化Observer对象,并将该对象传给Signal的observe()方法。稍后会给出该扩展方法的使用过程。

  • observeResult(result):该扩展方法是将Observer的value事件和failed事件分别转换成Result枚举的success和failure。

  • observeCompleted(completed): 该扩展方法所接收的闭包就是Observer接收completed事件所执行的闭包。

  • observeFailed(failed): 该扩展方法所接收的闭包就是Observer接收failed事件所执行的闭包。

  • observeInterrupted(interrupted): 该扩展方法所接收的闭包就是Observer接收interrupted事件所执行的闭包。

从下方代码片段中我们不难看出,都是在Signal的observe()方法的基础上做的扩展,本质上就是observe()方法的特定使用的快捷方式。

  

2、上述扩展的使用方式

看完实现,在看上述方法的使用方式就简单多了。下方代码片段就是上述扩展中每个方法的使用方式。我们可以根据具体的业务场景以及具体的功能来选择实现那种方法来满足自己的开发需求。从下方每个方法中的调用方式可以看出,每个方法在调用时所提供的尾随闭包就是该方法所表示的快捷方式。

当然,下方所有的方法,我们都可以使用Signal中的observe()方法来实现,只不过没有下方这些方法方便快捷。

  

二、SignalProtocol的Map扩展

在《ReactiveSwift源码解析之Event与Observer》这篇博客中我们聊了Event的Map函数,主要是将一个类型的Event(如Event<Value, Error>)转换成另一个Event类型(如Event<U, Error>)。Signal的Map函数也不例外,也是将一个类型的Signal转换成另一个类型的Signal。当然,Signal的Map函数本质上还是使用了Event的Map函数。

根据之前对ReactiveSwift框架的解析,我们不难发现Signal、Observer以及Event三者要想进行沟通是其泛型类型必须是相同的,也就是一套的。Map函数就是为了解决Signal类型与Observer的类型不匹配而生的。也就是说我们可以通过Map函数的处理,一个Int类型的Signal可以发送给String类型的Observer的,如果没有Map函数的支持,是做不到这一点的。

可以说Map函数是“适配器模式”的一种应用方式。可以将不同类型的信号量和观察者进行适配使其正常通信。接下来我们就来看一下SignalProtocol协议的Map相关的扩展以及使用方式。

1、map<U>() -> Signal<U, Error> 映射函数

map<U>()就是扩展中的Map相关函数之一。该函数是一个泛型函数,其返还值是一个Signal<U, Error>类型的对象。也就是说,一个Signal<Value, Error>类型的信号量可以通过map<U>()函数映射成一个Signal<U, Error>类型的信号量。当然map<U>()函数的参数是一个尾随闭包,该闭包有map函数的调用者提供,目的就是为了让用户自定义两个信号量之间的映射规则。

首先我们来看一下map函数的使用方式,下方代码片段中是map函数的使用示例以及输出结果,下方是对这段代码的解释:

  • 首先我们通过Signal的pipe()静态方法创建了一个类型为Signal<Int, NoError>的信号量signal。

  • 然后通过signal的map函数创建了一个新的类型为Signal<String, NoError>的信号量mappedSignal。map函数的尾随闭包中就是映射规则,其中value是Int类型,而返回值是String类型。

  • 然后创建了一个Observer<String, NoError>类型的观察者subscriber, 并将subscribermappedSignal进行关联

  • 最后我们调用signalobserver对象发送value事件,该事件所携带的值为整数10。由输出结果我们可以知道,与mappedSignal关联的观察者subscriber尽管只接收String类型的事件,但是经过map函数的处理此刻也是可以收到来自signal的整数值信号量的。

  

看完map函数的用法后我们来看一下其具体的代码实现。下方就是上述示例所调用的map()函数的具体实现代码。在map()函数中返回了一个类型为Signal<U, Error>的信号量对象。在Signal的构造器的尾随闭包中又调用了observe(action)方法将新创建的Signal的observer对象所对应的action添加到了之前Signal对象中。

  

上述代码的执行过程也许有些绕,我们可以通过一张简图来看一下上述代码的执行过程。下方是对该过程进一步的解释:

  • 首先类型为Signal<Value, Error>的signal对象调用其map<U>()函数生成了一个新的类型为Signal<U, Error>的newSignal对象。

  • 然后通过Event的map<U>()函数,将signal对象中类型为Event<Value, Error>的事件通过调用事件的map<U>()函数将其映射成类型为Event<U, Error>的newEvent事件对象。

  • 然后我们将新的newEvent添加到newSignalobserveraction中。

  • 然后使用newSignalobserver的action创建一个类型为Observer<Value, Error>的newObserver对象。

  • 最后将这个新的newObserver对象添加到旧的signalBag中。

  

上述是代码的调用步骤,我们可以看一下具体的执行过程,如下图所示。从下图的结构我们不难看出map()函数是链式发展的,下发的mappedSignal还可以调用其自己的map()函数来生成新的Signal对象。在这个链上的所有Observer都会接受到最原始的Signal对象所发出的事件消息。signal与mappedSignal桥接的最终手段还是Event的map()函数。

2、mapError<F>() -> Signal<U, F> 映射函数

mapError<F>()映射函数的实现机制和使用方式与上述的映射函数即为相似。只不过该映射函数使用了Event的mapError<F>()函数。因该映射还是的实现方式与上述函数类似,在此就不做过多赘述了。

关于lazyMap<U>()的实现和使用方式,我们暂且不说,后边聊到SignalProducer以及Flatten时我们再做补充。

三、SignalProtocol的filter扩展

Filter顾明思议,就是用来过滤东西的。如果你理解上述map的工作原理的话,Filter就显得简单多了。Filter的工作原理以及实现方式与map相似,只不过将Event的map改成了过滤条件。首先我们将会给出Filter的使用方式,然后在该处Filter的代码实现方式并给出工作原理图。

1、Filter的使用方式

关于Filter的使用,我们就使用ReactiveSwift官方的示例,下方是对该示例的解释:

  • 首先使用pipe创建一个signal,然后获取到该signal发送消息的句柄observer。

  • 然后通过调用signal的filter()函数来获取过滤信号量filteredSignal,filter()函数的尾随闭包中跟着的是过滤条件。

  • 然后往filteredSignal信号量中添加观察者subscriber。

  • 当使用signal信号量发送事件时,符合过滤条件的事件才会被过滤信号量filteredSignal所关联的观察者接收

下方截图中我们的过滤条件是事件绑定的值必须大于12,也就大于12的Value事件才会被观察者接受,所以输出的结果只有13和14两个,具体如下所示。

  

2、Filter的代码实现

看完Filter的使用方式,接下来我们来看一下Filter的代码实现方式。下方代码片段就是filter函数的具体实现,从代码结构上来看,与上述的map函数差不多,都是返回一个新的Signal对象,新的Signal对象与原来的Signal对象之间有一个桥接观察者来进行通信的。self.observer()函数后边的闭包就是桥接观察者从原信号量中发出的事件,然后在该事件中根据过滤条件来判断是否向新的信号量所绑定的所有观察者转发该事件。

从下方代码中我们明确的可以看出,当条件闭包predicate()的值为true时,observer就会对值的事件进行转发,然后过滤信号量所绑定的观察者就可以收到这些事件了。

  

3、执行原理图

下方就是filter的执行原理图,该图的结构与map()函数的执行结构类似。从下方图中我们不难看出,filter()函数也是支持链式发展的,就是可以在新的filterSignal的对象上我们任然可以添加新的过滤条件条件。因为无论是map()还是filter()函数都会返回一个新的Signal对象,并且两者都是可以链式发展的,所以我们可以这样去写signal.map().filter().map().filter().filter()……

在filter下方还有一个filterMap<U>()函数,该函数的主要功能是用来Map的,代码实现方式与与上述的filter类似,只不过是map的功能,但是该map功能有过滤功能,可以过滤掉nil的值。扩展中的skipNil()方法中调用的就是filterMap<U>()函数,在此就不做过多赘述了。

今天的博客就先到这儿,下篇博客我们会继续解析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 { }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #08fa95 }
span.s1 { }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #ffffff }
span.s1 { }

ReactiveCocoa源码解析(五) SignalProtocol的observe()、Map、Filter延展实现的更多相关文章

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

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

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

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

  3. Celery 源码解析五: 远程控制管理

    今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...

  4. dubbo源码解析五 --- 集群容错架构设计与原理分析

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...

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

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

  6. Spring 源码解析之DispatcherServlet源码解析(五)

    spring的整个请求流程都是围绕着DispatcherServlet进行的 类结构图 根据类的结构来说DispatcherServlet本身也是继承了HttpServlet的,所有的请求都是根据这一 ...

  7. iOS即时通讯之CocoaAsyncSocket源码解析五

    接上篇:iOS即时通讯之CocoaAsyncSocket源码解析四         原文 前言: 本文为CocoaAsyncSocket Read篇终,将重点涉及该框架是如何利用缓冲区对数据进行读取. ...

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

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

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

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

随机推荐

  1. windows 上优雅的安装 node 和 npm

    windows 的一键安装包,应该是最简单的 node 安装方式. 其实很多软件,拷贝过来就可以运行,根本不需要所谓的"安装"过程. 新建一个目录专门了管理 node 和 npm  ...

  2. 《Android进阶》之第三篇 深入理解android的消息处理机制

    Android 异步消息处理机制 让你深入理解 Looper.Handler.Message三者关系 android的消息处理机制(图+源码分析)——Looper,Handler,Message an ...

  3. 11154 LRC才不会告诉你们的事情

    #include<stdio.h> #include<string.h> int main() { ,t=; ],sum[],k=,d=; ]; ]; scanf(" ...

  4. 开涛spring3(3.1) - DI的配置使用

    3.1.1  依赖和依赖注入 传统应用程序设计中所说的依赖一般指“类之间的关系”,那先让我们复习一下类之间的关系: 泛化:表示类与类之间的继承关系.接口与接口之间的继承关系: 实现:表示类对接口的实现 ...

  5. STM32伺服编码器接口

    在STM32的高级定时器和一般定时器中有Encoder interface mode(编码器接口),TI1和TI2分别对应TIM_CH1 和TIM_CH2 通道. 一.计数规则如下: 表55的是编码器 ...

  6. android studio 2.32躺坑记

    按说这是没啥记录意义的.不过作为一个偶尔用一下ADT开发安卓程序的跨界老码农,遇到一个尴尬事,现在手机已经用上安卓6了,而电脑里的ADT里SDK还是18,19.越来越多的项目是android stud ...

  7. 06.04 html

    域名跟ip地址是绑定的看某个网站的ip地址 可以ping网址知道ip地址   最终访问的都是ip地址  每个ip地址都对应了一个空间(一块区域 要用来存储内容)网页访问的原理: 客户端电脑发动请求到服 ...

  8. SQL数据库的多表查询

    多表查询分为 内.外连接 外连接分为左连接(left join 或left outer join).右连接(right join 或者 right outer join).和完整外部连接 (full ...

  9. Python常用的第三方库

    最近学习python 做些数据挖掘相关的练习,涉及到很多第三方的库,所以做一总结. Setuptools 可以让程序员更方便的创建和发布 Python 包,特别是那些对其它包具有依赖性的状况. 我特别 ...

  10. iOS CAEmitterLayer 实现粒子发射动画效果

    iOS CAEmitterLayer 实现粒子发射动画效果 效果图 代码已上传 GitHub:https://github.com/Silence-GitHub/CoreAnimationDemo 动 ...