ReactiveCocoa这个框架是作什么用的本篇博客就不作过多赘述了,什么是“响应式编程”也很少聊了,自行Google吧。本篇博客的主题是解析ReactiveCocoa框架中的核心模块ReactiveSwift中的两个核心类的实现,也就是对Event和Observer这两个类进行解析。之因此把这两个类放在一块聊,是由于这两个类比较独立,能够说是ReactiveSwift中的两个原子类。Event确切的说是一个枚举,其中有几种事件,而Observer类的对象就是这些事件的发送者。因此把这两个类放在一块是比较合适的。html
固然确切的说,本篇博客是对 ReactiveSwift框架 的部分解析,而ReactiveCocoa这个框架又是在ReactiveSwift框架的基础上搭建起来的,因此咱们先来看一下ReactiveSwift这个框架中的代码实现。固然,咱们以前发表过ReactiveCocoa的相关博文,如《iOS开发之ReactiveCocoa下的MVVM》,该篇博客的主题仍是ReactiveCocoa框架的应用,而本篇博客或者说ReactiveCocoa源码解析系列博客是对ReactiveCocoa框架实现的深度解析。固然这种深度解析有一部分是Swift语言层面的,由于ReactiveCocoa框架中有好多Swift语言的高级用法,固然还有一些架构层面的,经过源码实现,咱们要分析出这样设计的好处以及优势。android
抛去“响应式编程”的概念,ReactiveCocoa的本质仍是对“观察者模式”的使用,关于观察者模式,请参考以前的博客《设计模式(二):本身动手使用“观察者模式”实现通知机制》。也能够说ReactiveCocoa是“观察者模式”应用中比较牛X的一个框架。固然,框架在编码实现时还用到了其余设计模式,在解析到相关内容时,咱们在对其进行概述。git
固然,本篇博客是对ReactiveSwift源码的解析,也就是说你能够在你的工程中仅仅的引入 ReactiveSwift框架 ,GitHub地址为:https://github.com/ReactiveCocoa/ReactiveSwift.git,至于如何将ReactiveSwift引入到的你的工程中,请参考ReactiveSwift下方的README, 固然,本篇博客是使用的Cocoapods来实现的版本管理,固然ReactiveSwift也支持Carthage, 若是你是Mac开发的话,还可使用Swift自带的包管理器。Swift的包管理器咱们在以前聊Swift开发服务端的时候使用到了,不过目前iOS开发中还不能使用Swift自带的包管理器。相信在不久的未来Swift的包管理器将会支持iOS开发的。闲淡适中,开始咱们的主题。github
本篇博客咱们将先在Swift语言的层面来聊一些东西,由于在Event和Observer实现时会用到。而后咱们再解析一下Event和Observe的实现。以前咱们聊过Swift语法层面的东西,不过今天仍是要在聊一下的,结合着实例还聊语法最为实用。编程
1、Swift中的泛型设计模式
在ReactiveSwift以及ReactiveCocoa中大量的用到了泛型以及关联类型,因此在聊源码以前,咱们仍是有必要回顾一下Swift中的泛型的使用的。固然,只是简单的回顾一下,不是今天博客的重点。首先咱们得经过一个实例来看一下泛型的使用。闭包
下方这个代码段,就是在协议中使用 associatedtype 关键字声明了一个关联类型,固然这个关联类型就至关于协议中的泛型了。下方的这个 GenericityClass 类后边的<>中声明的就是该类中使用的泛型类型,咱们将该泛型命名为 MyCustomType, 固然咱们要求该类型必须是遵循 Comparable 协议的类型,因此声明该泛型的形式为 <MyCustome: Comparable>。声明完该泛型后,在类中咱们就能够想使用普通类型那样来使用该泛型了。架构
泛型不只仅能够在类中使用,也能够在方法中使用,下方的genericityFunc()方法中就使用了泛型,用法就是在方法名的后方紧跟着泛型,以下所示。框架
接下来咱们来看一下上述泛型类的使用方式。下方代码首先声明了一个泛型类的实例,在实例化时,给泛型指定了肯定的类型 String。咱们还能够为相应的的泛型类型使用 typealias 指定别名,而后使用别名来实例化,以下所示。由于代码比较简单,下方测试用例的输出结果就不往上粘贴了。函数
2、Swift中的枚举
由于今天咱们要聊的Event就是个枚举,因此咱们先来回顾一下Swift中枚举的使用。固然仍是依托于实例。下方代码中的枚举是在咱们以前聊Swift的枚举的主题中拿过来的,而且作了相应的修改。固然在Swift中枚举以及结构体都是可使用泛型的,接下来咱们就来好好看一下Swift中强大而灵活的枚举类型。
下方代码片断中咱们定义了一个MobileLanguage枚举类型,其中有两个枚举项。一个是iOS,另外一个是Android。枚举项iOS的枚举关联值是一个含有两个字符串元素的元组,而Android枚举项的关联值是一个字符串。下方的iOSValue和androidValue是两个计算属性,用来返回相关枚举项的关联值。
固然,咱们使用 if-case-let语句来获取相关的枚举关联值,具体以下所示。
固然,咱们还能够对 “==”运算符进行重载,让其支持上述定义的枚举类型的比较。下方主要仍是Switch的使用,固然,以前咱们也针对过Switch单独进行过讲解,下方就是Switch对元组的匹配,而且在相应的case中获取枚举的关联值,以下所示。
下方就是上述枚举的使用与输出结果,以下所示:
3、ReactiveSwift中的Event的实现
接下来咱们就来分析一下ReactiveSwift框架中的Event枚举的代码实现。我先看其源码,而后再看其使用方式。
一、Event中的事件类型
下方截图中就是Event枚举类型中所包含的全部枚举项。从下方代码中咱们能够看出,Event后方跟了两个泛型,一个是Value,另外一个是遵循Swift.Error协议的Error泛型。而后紧跟着的是Event枚举中的几个事件类型。下方是对这几种类型的介绍:
value: 用来关联信号量所传送过来的值,该值的类型就是上面定义的Value泛型。
failed: 表示因错误而被迫停止的事件,其关联值是相关的错误信息。
completed: 该事件是完成事件,也就是全部的东西都success,正常终止。
interrupted: 该事件表示被迫中断的事件,也就是没有达到预期效果,被迫停止。
二、Event中的 isCompleted 和 isTerminating计算属性
这两个属性是计算属性,下方是其实现代码。isCompleted 用来判断该事件是不是正常完成的事件,而isTerminating主要用来判断事件是否已经终止,固然其中包括异常终止。固然这两个计算属性也是比较简单的,就是根据不一样的条件返回不一样Bool值便可。
三、Event中的 value 和 error 计算属性
下方这两个也是计算属性,主要是经过 if-case-let 语句来获取枚举的关联值,并与相应的计算属性进行关联。value属性则用来获取枚举项.value所关联的值。而error则用来获取枚举项.failed所关联的值。具体代码以下所示。
四、Even计算属性的测试
接下来,咱们就对上述的计算属性进行测试。下方这段代码就是对上述计算属性的测试。首先咱们建立了一个类型为 Event<Int, NSError>类型的事件。该事件所关联的值为100,而后咱们输出计算属性value、isTerminating、isCompleted计算属性的值进行打印,具体打印结果以下所示。
而后咱们又建立了一个错误类型的事件errorEvent。并给该枚举项关联一个NSError类型的错误对象。而后对error、isTerminating、isCompleted的值进行打印。从打印结果能够看出isTerminating为true,说明是终止事件,而isCompleted为false,则说明是非正常终止。
五、Event中的map函数
在Event枚举中,主要有两个map函数,一个是map<U>()泛型函数。另外一个是mapError<F>()泛型函数。由于mapError<F>()函数的实现与map<F>()函数的实现极为类似,咱们此处就以mapError<U>()泛型函数为例。也就是下方这个完整的函数。
map<U>()函数是一个泛型函数,在函数名map后紧跟的<U>就是咱们定义的泛型。而该函数的参数是一个闭包 f, 该闭包的类型为 (Value) -> U。也就是说该闭包的有一个Value类型的参数,而且返回一个U类型的返回值。map<U>()这个函数的返回值是一个新的事件,该事件的类型为Event<U, Error>。通过这么一分析,map<U>()函数就是将当前的 Event<Value, Error> 类型的事件映射成Event<U, Error>类型的事件。固然此处的Value和U都是泛型,固然若是换成具体的参数的话,也就是说一个 Event<Int, Error> 类型的参数能够经过下方的方法来映射成 Error<String, Error> 类型的事件。
下方咱们须要主要的是返回值 .value( f(value) ) 这句话,.value()的关联值是f(value)这个闭包所返回的值,而f(value)这个闭包的参数是以前事件所绑定的值。而f(value)所返回的值就是要映射的结果类型。f()的闭包体由用户来提供,也就是说用户能够自定义映射规则。
六、map函数的测试用例
接下来咱们来看一下Map函数的使用方式。下方代码段就是Map函数的测试用例以及运行结果。首先咱们建立了一个类型为 Event<Int, NSError> 类型的事件,而后该事件的value值为100。 而后咱们调用map函数将 Event<Int, NSError> 类型映射成 Event<String, NSError>类型。而后map函数后边跟随的尾随闭包就是咱们的映射规则。你能够在该闭包中添加任意的映射规则,将原来的值转换成你想要的值。
mapError<F>()函数的实现以及使用方式,与上述函数相似。接下来咱们就来看一下mapError<F>()函数的使用方式。首先咱们定义了两个错误类,一个是MyError另外一个是MyError1。而且定义了一个Event<Int, MyError> 类型的错误事件,而后调用 mapError<F>()函数将其转换成 Event<Int, MyError1> 类型的事件,固然调用时提供的闭包仍然是映射规则。具体以下所示。
Event枚举中还有对 == 号运算符的重载,使Event类型的参数支持 == 运算符。其中还有一个将事件类型转换成description描述字符串的 extension。由于其内容比较简单,在此就不作过多赘述了。
4、ReactiveSwift中的Observer
聊完Event的实现,咱们来看一下Observer类的实现。Observer的主要职能是对Event进行使用,也就是Observer能够调用本身的方法来发送Event中所提供的各类事件的。下方就是对Observer类的详细解析。
一、Observer类中属性以及构造器的解析
接下来咱们来看一下Observer类中所声明的属性以及构造器。首先咱们注意到,Observer类也是也一个泛型类,在Observer类名后方分别跟着 Value 和Error: Swift.Error两个泛型。这两个泛型分别与Event后边的泛型相对应,Value就是事件所关联值的类型,而Error就是发生错误时错误的类型。
紧接着是声明了一个 (Event<Value, Error>) -> Void 的闭包类型,而且为该类型声明了一个Action的别名。而后使用这个Action的别名声明了一个action的不可变属性。而Observer的构造器的参数就是一个类型为(Event<Value, Error>) -> Void 的闭包。
Observer还声明了一个便利构造器。该便利构造器有四个可选类型的参数,每一个参数的类型都是一个闭包。这四个可选类型的闭包参数分别与Event中的四种事件相对应,在便利构造器中调用Observer的构造器时,提供了Action闭包的闭包体,在Action闭包体中,根据具体的事件类型来执行便利构造器参数所提供的相应闭包参数。固然便利构造器的闭包参数由Observer的使用者所提供,用来回调相应事件中的值。
根据上面的源代码咱们不难看出,在初始化Observer的对象时,咱们能够调用构造器,也能够调用便利构造器来进行初始化。固然,仍是推荐使用便利构造器来实例化Observer类的实例。下方第一个就是使用的便利构造器来实例化Observer的,而且在调用是提供了四个闭包回调,来分别处理Observer发来的不一样事件。
固然你也能够直接调用 Observer所提供的构造器,也就是直接为Action闭包赋值。第二段代码中的尾随闭包就是Action的闭包体,固然咱们须要本身处理Action针对不一样事件是所给出的处理块。
二、Observer中发送事件的方法sendXXX()
接下来咱们就来看一下Observer中发送各类事件的方法,固然Event有四种事件类型,那么Observer中也就是是4个发送事件的方法了。下方代码片断就是Observer中发送事件的方法,从下方的方法中咱们不难看出,发送事件其实就是对 action闭包的调用,而且传入相应的事件。在调用 action 闭包时,就会执行咱们所提供的或者遍历构造器中所提供的闭包体,将发送的事件回调出去。
三、sendXXX()方法的测试用例
上面咱们已经经过Observer的构造器和便利构造器实例化两个实例,接下来咱们就调用这些实例所对应的send方法。下方代码片断就是对相应Observer实例的相关send方法的执行。
下方就是上述测试用例的执行结果
5、Observer工做的流程图
看完上述代码,由于闭包回调会致使一些代码的执行流程已经调用关系不太容易理解,解析来咱们就来画一个图来简述Observer的具体工做过程。下方代码就是上述测试用以的执行以及调用的过程。
下方是一个完整的程序执行过程,输入->处理->输出。
因篇幅有限,今天的博客就先到这儿,下篇博客咱们会继续解析ReactiveSwift框架中的其余内容。
上述代码github分享地址:https://github.com/lizelu/TipSwiftForRac