ReactiveSwift源码解析(二) Bag容器的代码实现
今天博客我接着上篇博客的内容来,上篇博客我们详细的看了ReactiveSwift中的Observer已经Event的代码实现。接下来我们来看一下ReactiveSwift中的结构体Bag的实现。Bag:袋子,顾明思议,就是用来装东西的,我们暂且将Bag称之为容器。在ReactiveSwift中的Bag主要是用来存储Signal对象的,我们在后期介绍ReactiveSwift源码时会陆陆续续的看到Bag的身影。
因为Bag这个结构体在ReactiveSwift中比较独立,所以我们本篇博客就来聊一下Bag的具体实现。本篇博客我们会详细的介绍Bag的代码实现,并从Bag代码实现中看一下Swift语言本身的东西,并给出Bag的测试用例。当然,本篇博客我们还会涉及到“迭代器模式”,关于“迭代器模式”更详细的信息,请移步于之前发布的关于设计模式的博客《设计模式(十):从电影院中认识"迭代器模式"(Iterator Pattern)》。
一、ContiguousArray
在博客的第一部分我们先来看一下ContiguousArray的相关内容。因为结构体Bag就是在ContiguousArray的基础上进行封装的,也就是说袋子中的元素最终是存放在ContiguousArray中的。在Swift中ContiguousArray与Array的用法差不多,下方是官方对ContiguousArray的介绍。
从下方我们可以清楚的知道ContiguousArray、Array还有ArraySlice的大部分属性和方法是共用的。但是在存储Class或者@objc 协议时,使用ContiguousArray效率会更高一些。但是ContiguousArray不能和Objective-C的NSArray进行桥接,并且不能将ContiguousArray传入到Objective-C的API中。
当然从ContiguousArray名字来看,它是占用连续存储空间的数组。具体请看下方的官方介绍。
二、Bag的基本实现
下方是结构体Bag的基本实现,稍后还会介绍Bag的延展以及与其关联的BagElement类型。接下来我们来详细的看一下其实现。当然下方截图中的代码实现,是将ReactiveSwift中的英文注释给删了,添加了一些中文注释。这样看着更舒服一些。
1、RemovalToken
首先我们来看一下RemovalToken,以及看一下RemovalToken这个类在Bag结构体中所扮演的角色。从下方代码片段中我们不难看出,RemovalToken是一个空类,中该类的名字我们可以看出,该类的对象是充当Token用的。也就是说该类的对象可以作为Bag中所存储元素的唯一标示符,并且可以用来删除元素使用。
我们知道,每个类的对象都会有一个唯一的HashValue。其实在Bag中真正使用到的是RemovalToken的对象所对应的HashValue,这个稍后我们会聊到。
2.Bag的基本实现
从下方代码段中,我们可以看出Bag是以结构体的形式存在的,而且后边紧跟了一个Element的泛型类型。紧接着是类型为 ContiguousArray<BagElement<Element>> 的泛型数组,BagElement<Element>这个类型稍后会提到。
insert()方法负责插入元素,从代码实现来看其实就是向elements数组后方append元素,添加的元素类型为BagElement。inser()方法由@discardableResult进行修饰,说明insert()方法所返回的值可以被忽略,也就是说如果没有变量来接收insert()的返回值的话,程序并不会报出警告。而insert()前方的 mutating关键字一般用来修饰Swift中的枚举或者结构体中的方法,被mutating关键字修饰的方法就可以修改枚举或者结构体中的属性了。用法如下所示。
接下来我们来看一下remove()方法,该方法的参数是一个token,其功能就是通过token来删除元素。当然具体代码实现也是比较简单的,就是对elements数组进行遍历,找到元素的token与传入的token一致的话,我们就将其删除。具体实现如下所示。
三、BagElement结构体的实现
接下来,我们来看一下Bag中所存储元素的类型BagElement的实现,代码如下所示。当然实现比较简单,BagElement也是一个泛型结构体,其泛型类型Value其实就是Bag的泛型类型Element。其中有两个属性,一个Value,用来存储值。另一个是token,用来存储该值对应的唯一标示。
紧接着是BagElement的的延展,用来输出描述信息的,如下所示。
四、Bag的延展
接下来我们来看一下Bag的延展,代码如下所示。Bag的延展中的相关内容还是比较简单的。首先定义了一个Array<Element>.Index的类型别名Index,其实就是Int类型。然后是startIndex和endIndex两个计算属性,用来获取Bag的第一个元素的索引,和结束位置的索引。
subscript()方法是为Bag结构体添加自定义下标,使其支持下标访问元素的形式。makeIterator()方法则用来创建Bag<Element>所对应的迭代器。关于Bag的迭代器,稍后会进行介绍。
五、Bag的迭代器
接下来我我们就来看一下Bag容器的迭代器,其实就是“迭代器模式”的具体应用。下方代码段就是Bag的迭代器的具体实现。从下方代码我们不难看出,BagIterator实现了Swift中的迭代器协议IteratorProtocol,然后给出了迭代器的next()方法的实现。下方我们将会对该迭代器进行测试。
六、Bag的测试用例
下方代码片段中是对Bag的测试用例。首先我们初始化了一个Bag实例,然后指定其泛型类型为String。紧接着我们又创建了一个bagsTokens的数组,用来存储myBags中每个元素所对应的token,便于在移除元素时使用。最后是往myBags中添加值了。每添加一个值我们就记录一下该值所对应的token。
在添加完元素后,我们可以遍历输出一下每个token对象的HashValue。然后我们可以通过token来移除myBags中的元素。
最后我们可以从myBags中获取相应的迭代器,然后使用迭代器访问myBags中的元素。
下方是对Bag中的Token以及Bag中的所有元素进行的输出,如下所示:
今天博客就先到这儿,下篇博客会继续更新ReactiveSwift相关的东西。
上述代码github分享地址:https://github.com/lizelu/TipSwiftForRac
ReactiveSwift源码解析(二) Bag容器的代码实现的更多相关文章
- ReactiveCocoa源码解析(二) Bag容器的代码实现
今天博客我接着上篇博客的内容来,上篇博客我们详细的看了ReactiveSwift中的Observer已经Event的代码实现.接下来我们来看一下ReactiveSwift中的结构体Bag的实现.Bag ...
- ReactiveSwift源码解析(一) Event与Observer代码实现
ReactiveCocoa这个框架是做什么用的本篇博客就不做过多赘述了,什么是"响应式编程"也不多聊了,自行Google吧.本篇博客的主题是解析ReactiveCocoa框架中的核 ...
- ReactiveSwift源码解析(三) Signal代码的基本实现
上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...
- ReactiveSwift源码解析(五) SignalProtocol的observe()、Map、Filter延展实现
上篇博客我们对Signal的基本实现以及Signal的面向协议扩展进行了介绍, 详细内容请移步于<Signal中的静态属性静态方法以及面向协议扩展>.并且聊了Signal的所有的g功能扩展 ...
- Mybatis源码解析(二) —— 加载 Configuration
Mybatis源码解析(二) -- 加载 Configuration 正如上文所看到的 Configuration 对象保存了所有Mybatis的配置信息,也就是说mybatis-config. ...
- RxJava2源码解析(二)
title: RxJava2源码解析(二) categories: 源码解析 tags: 源码解析 rxJava2 前言 本篇主要解析RxJava的线程切换的原理实现 subscribeOn 首先, ...
- Sentinel源码解析二(Slot总览)
写在前面 本文继续来分析Sentinel的源码,上篇文章对Sentinel的调用过程做了深入分析,主要涉及到了两个概念:插槽链和Node节点.那么接下来我们就根据插槽链的调用关系来依次分析每个插槽(s ...
- vueJs 源码解析 (三) 具体代码
vueJs 源码解析 (三) 具体代码 在之前的文章中提到了 vuejs 源码中的 架构部分,以及 谈论到了 vue 源码三要素 vm.compiler.watcher 这三要素,那么今天我们就从这三 ...
- Spring5源码解析_IOC之容器的基本实现
前言: 在分析源码之前,我们简单回顾一下SPring核心功能的简单使用: 容器的基本用法 Bean是Spring最核心的东西,Spring就像是一个大水桶,而Bean就是水桶中的水,水桶脱离了水就没有 ...
随机推荐
- UDP和TCP的差异
UDP和TCP传递数据的差异类似于电话和明信片之间的差异. TCP就像电话,必须先验证目标是否可以访问后才开始通讯. UDP就像明信片,信息量很小而且每次传递成功的可能性很高,但是不能完全保证传递成功 ...
- jmeter添加断言
先创建一个线程组,再创建一个http请求. 为了方便观察,我们添加两个监听器,察看结果树和断言结果. 添加断言:响应断言,响应断言也是比较常用的一个断言 设置响应断言:正常情况下响应代码是200.选择 ...
- Eclipse报错Resource '/.org.eclipse.jdt.core.external.folders/.link5' already exists.
Eclipse查看源码出现source not found,重新Build Path选择jdk的jar包时,出现Resource '/.org.eclipse.jdt.core.external.fo ...
- leetcode 26 80 删除已排序数组中重复的数据
80. Remove Duplicates from Sorted Array II Follow up for "Remove Duplicates":What if dupli ...
- Spring MVC温故而知新 – 请求映射RequestMapping
RequestMapping注解说明 @RequestMapping注解的作用将Web请求映射到特定处理程序类和/或处理程序方法,这个注解可以用于类或者方法上,并通过属性value指定请求路径.用在C ...
- 在Windows Server 2008 R2下搭建jsp环境(四)-在测试的过程中可能出现的问题
环境基本部署好了之后,便开始测试,一定要让他经得起"考验",他才会值得你的信赖.Tomcat服务器部署成功的的验证方法(默认端口的情况下): 1.loacalhost:8080 2 ...
- BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序
BZOJ_4867_[Ynoi2017]舌尖上的由乃_分块+dfs序 Description 由乃为了吃到最传统最纯净的美食,决定亲自开垦一片菜园.现有一片空地,由乃已经规划n个地点准备种上蔬菜.最新 ...
- ES6知识整理(1)--let和const命令
最近准备在业余空闲时间里一边学习ES6,一边整理相关知识.只有整理过的学习才是有效的学习.也就是学习之后要使用和整理成文,才是正在的学到了... 那么现在开始 LINK START!(首先是第一讲,前 ...
- html中 submit和button的区别?
前者是向数据库提交表单 后者是单纯的按钮功能
- Extjs中数据导出到Excel
1.前端代码(URL+前端传入参数) window.location.href="studnetMaintainAction!exportExcel" ...