ReactiveSwift源码解析(十) Lifetime代码实现
为了之后博客的进行,本篇博客我们就来聊一下ReactiveSwift框架中的Lifetime类的具体实现。从Lifetime这个名字中我们就这道,就是生命周期。在ReactiveSwift中使用Lifetime来标记一个对象的生命周期,其实主要功能还是将对象的deinit()析构函数通过发送信号量将其回调出来。接下来我们就来看一下Lifetime类的实现。Lifetime类与Event和Observer相似,也是比较原子性的类,以原子组件的形式存在于ReactiveSwift中。
下方我们会先给出一个Lifetime的使用示例,然后根据示例的输出结果来看一下Lifetime的具体代码实现,以及工作原理。
一、Lifetime使用实例
针对Lifetime的特性,我们给出了下方的示例。当然ReactiveSwift官网上是没有关于Lifetime的单独示例的,因为Lifetime不单独的对外服务。下方就是我们对Lifetime类而写的示例。
1、lifetime()方法实现
首先我们来看一下下方的lifetime()方法。。首先通过Lifetime类中的make()工厂方法创建了一个Lifetime的对象和该对象对应的token。并且lifetime()方法在调用时,需要一个引用参数tokenRef,也就是说tokenRef是inout类型的参数,通过tokenRef参数可以把make()所返回的token传到函数外部。
然后使用lifetime对象的observeEnded()方法来添加两个观察者。后边紧跟着的尾随闭包是token被释放时所执行的闭包块。因为lifetime对象除了在lifetime()方法中使用到,再也没有其他地方的引用了,根据ARC中Strong类型的特点,所以在lifetime()方法调用结束后lifetime对象就会被释放掉。所以我们在lifetime()函数的结尾处给出了“lifetime将要被释放”的Log。
而lifetime()方法中的token对象通过tokenRef这个inout类型的参数被方法之外的作用域使用到,所以在lifetime()方法调用结束后token所对应的堆空间并不会被释放。
2、lifetime()方法的调用
在tapLifetimeButton()方法中,我们对上述的lifetime()方法进行了调用。首先我们声明了一个类型为Any?的tokenRef变量,该变量在调用lifetime()函数时作为参数传给lifetime()方法。也就是说tokenRef变量引用了lifetime()方法中的token对象所对应的堆空间。
当lifetime()被调用后,因为lifetime()中的lifetime对象所对应的堆空间只用在lifetime()的作用域中被引用到,所以当该方法执行完毕后,lifetime所对应的堆空间会立即被释放掉。
当tokenRef被置为nil后,token所对应的堆空间也会被立即释放掉。在token被释放执行token对应的析构函数时,会给那些通过lifetime的observeEnd()方法添加的观察者发送被析构的消息。所以token被释放时,会执行observeEnd()方法的尾随闭包。

3、运行结果
下方截图就是上述示例的运行结果,我们可以根据下方的输出结果与上述的代码实现进行对比。从输出结果中我们容易知道,lifetime对象是在lifetime()方法调用执行后所释放的。而在lifetime()方法中所分配的token对象所对应的堆空间是在tokenRef被置为nil时所释放的,在释放之前像观察lifetime的生命周期的观察者来发送消息。
从运行结果来看,Lifetime这个生命周期的类,本质上是通过token来标示一个对象的生命周期的,和Lifetime对象的释放是没有什么直接关系。稍后,我们聊Token类以及Lifetime类时,会一目了然。

二、Lifetime中的内部类Token
看完Lifetime的使用示例,我们来看一下Lifetime的内部代码实现。在Lifetime类的内部定义个了一个Token类。Token类的对象会在Lifetime中使用到,稍后会给出Token的使用方式。接下来我们就先来看看这个Lifetime类内部的Token类的代码实现。
Token类的实现比较简单,一句话概括Token的功能:其中使用了Signal的pipe方法创建了一个ended信号量,并获取到了ended信号量发送事件的endedObserver,然后在deinit析构函数中使用endedObserver的sendCompleted()的方法发送Complete事件。上这句话就概括了Token中的全部功能。
下方就是Token类的代码实现,其中有一点需要我们注意的是在Token的ended信号量所发送的Value值的类型是一个无参闭包。在之后的内容中,用到的时候在介绍。

三、Lifetime的ended属性和构造器
聊完Token的代码实现,我们就来聊一下Lifetime中的对象属性以及构造器。在Lifetime类中只有一个对象属性,那就是ended信号量。该信号量的类型也是一个可以发送无参无返回值的闭包的Value。Lifetime的构造器主要就是给ended赋值。具体代码如下所示。

四、Lifetime的便利构造器、工厂方法以及empty静态属性
1、Lifetime的便利构造器
接下来我们就来看一下Lifetime的便利构造器。下方代码片段中被convenience关键字修饰的就是Lifetime的便利构造器。该便利构造器的参数是一个Token类型的对象,而在便利构造器中调用了Lifetime的构造器,将Token对象的ended信号量传给了Lifetime的构造器。所以Lifetime中的ended信号量其实就是Token对象中的ended信号量。
2、Lifetime的工厂方法
聊完Lifetime的便利构造器后,我们就来聊一下Lifetime的工厂方法。我们在之前的博客中《设计模式(四):从“兵工厂”中探索简单工厂、工厂方法和抽象工厂模式》详细的介绍了工厂模式。而下方代码片段中的make()静态方法在Lifetime类中所扮演的角色就是工厂方法,负责创建Lifetime类的对象。在make()方法中主要做了两件事情,一个是实例化了一个Token对象token,然后将token传给Lifetime的便利构造器。最后将token以及Lifetime的便利构造器所创建的Lifetime类的对象以元组的形式进行返回。具体代码如下所示。
3、Lifetime的empty静态计算属性
Lifetime的empty静态计算属性类似于Signal的empty静态计算属性,从其实现代码我们可以看出empty所创建的Lifetime对象中的ended信号量是一个Signal.empty类型的信号量。也就是说empty所创建的Lifetime对象是一个已经结束的生命周期。具体代码如下。

五、observeEnded()方法实现
接下来我们来看一下observeEnded()方法的代码实现。该方法的主要目的就是往ended信号量中的Bag容器中添加观察者的。当观察者收到的事件是isTerminating时,会执行observeEnded()方法所提供的尾随闭包。
而这个endend信号量本质上就是token对象中的endend信号量。当token对象被析构时,会在token的析构函数中调用endend信号量发送信号的endendObserver的sendComplete()方法来发送complete事件,也就是上述代码在Token类的deinit方法中所作的事情。

六、Lifetime执行原理图
下方是Lifetime、Token、Signal、Observer间的执行关系图。在Lifetime类中,token起着至关重要的作用。Lifetime的工作原理中其实是使用Token的对象的生命周期来表示一个对象的生命周期的。如果Lifetime的对象空间被释放了,但是Token对象所对应的堆空间任然存在,那么Lifetime所对应的Object的生命周期任然再延续,这一点从上面的代码示例中可以明确看出。
还是那句话,本质上是使用Token对象的生命周期来表示一个对象的Lifetime。

今天的博客就先到这儿,下篇博客我们会继续解析ReactiveSwift框架中的其他内容。
上述代码github分享地址:https://github.com/lizelu/TipSwiftForRac。
ReactiveSwift源码解析(十) Lifetime代码实现的更多相关文章
- ReactiveSwift源码解析(三) Signal代码的基本实现
上篇博客我们详细的聊了ReactiveSwift源码中的Bag容器,详情请参见<ReactiveSwift源码解析之Bag容器>.本篇博客我们就来聊一下信号量,也就是Signal的的几种状 ...
- ReactiveSwift源码解析(十二) MutableProperty基本代码实现
前两篇博客我们分别聊了ReactiveSwift框架中的负责标记对象的生命周期的类Lifetime以及负责原子性操作的Atomic类的具体代码实现.前两篇博客之所以聊Lifetime以及Atomic的 ...
- 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 ...
- vue系列---Mustache.js模板引擎介绍及源码解析(十)
mustache.js(3.0.0版本) 是一个javascript前端模板引擎.官方文档(https://github.com/janl/mustache.js) 根据官方介绍:Mustache可以 ...
- Spring源码解析 - springMVC核心代码
一.首先来讲解下springMVC的底层工作流程 1.首先我们重点放在前端控制器(DispatcherServlet) 其类图: 因为从流程图看,用户的请求最先到达就是DispatcherServle ...
- Vue源码解析-调试环境-代码目录和运行构建
目录 前言 1 代码结构 1.1 octotree插件 1.2 vue工程项目目录 1.3 主要代码目录src compiler core platforms server sfc shared 2 ...
随机推荐
- 关于MATLAB收集人工鼠标移动轨迹的坐标
首先需要设计一个用户图形界面的函数,这个图形界面被用于在其上面绘制轨迹并记录当时的坐标. 该回响函数应包含:鼠标按下时,鼠标移动时,和鼠标释放时的反应命令.当然网上有有相关的开源 程序,但是有缺陷(该 ...
- Entity Framework入门教程:SQLite数据源访问
[环境安装] 可以通过NuGet直接搜索安装SQLite需要用到的组件 或者直接使用程序包管理器控制台 > Install-Package System.Data.SQLite 通过ADO.NE ...
- Lamp单独安装(windows下)
安装的软件清单:apache_2.2.9-win32-x86-openssl-0.9.8h-r2.msimysql-5.1.28-rc-win32.zipphp-5.2.6-Win32.zipphpM ...
- php防止浏览器点击返回按钮重复提交数据
<!--html中存放隐藏域数据--> <input type="hidden" value='{$sun_nums}' name='sub_nums' /> ...
- 解决yii框架,gii脚手架不能使用。
应用场景 把代码转移到线上服务器时,GII.BUG工具不正常使用,但在本地服务器是正常的. 分析原因 Yii框架在使用GII 和BUG 时,会针对访问IP地址拦截,没有在配置中设置的IP地址是会默认被 ...
- 简单粗暴的在vmware虚拟机中固定ip
虚拟机对于很多做测试的或者在学习测试中的人来说是位常客,经常会用到,但是虚拟机重启之后,很多人遇到虚拟机ip变化,很是头痛,我在学习过程中也遇到了这个问题,百度了很多办法,有些办法对于网络知识小白来说 ...
- 关于Android log拿不到的情况
遇到很多开发者说crash了,log没有看到..出现类似情况的基本原因是因为现在的国产厂商如crash了会直接将进程杀掉,于是你的studio就看不到了,可以往下面几个方向去想办法找到crash的lo ...
- 新浪微博share分享接口请求奇葩错误
17年6月30号,微博正式转入牛逼状态: 限制原来的微博发布删除等接口:(想用就开套餐,不然别说话) 开放新的分享接口share,然而,在调用这个分享接口时候,就会出现各种各样的奇葩错误: 注意事项: ...
- 使用express, create-react-app, mongodb搭建react模拟数据开发环境
提要 最近刚刚完成了一个vue的项目,其中涉及的用户数有6000多个以及其他数据也比较多,为了在前端能够真实的进行数据模拟,所有把全量数据拷贝下来放到了api.json中.这样导致整个api.json ...
- 51nod_1119:机器人走方格 V2
题目链接: https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1119 转化成杨辉三角就好辣@_@ #include< ...