ReactiveCocoa函数响应式编程-应用篇

使用RAC其实就是一个创建信号订阅信号的过程。上篇

ReactiveCocoa函数响应式编程-基础篇

,主要简单介绍了RAC的信号机制,本篇则以信号为核心,就信号常用的类、操作信号的方法,替换响应处理等方面总结RAC的使用。

目录:

一、RAC中常用的类

二、RAC中常用的宏

三、RAC中信号的常用操作

四、RAC常用的处理事件响应的方法

五、本篇总结

本篇还提供了关于RAC使用的两个测试工程,结合代码学习更加直观

项目1

https://github.com/DreamcoffeeZS/ReactiveCocoaDemo

1.测试RAC对信号的各类操作。

2.使用RAC改进一个普通的登录界面。

项目2:

https://github.com/DreamcoffeeZS/MVVMReactiveCocoa

MVVM架构结合RAC响应式编程的开发示例。实现登录界面和的分页数据界面。效果图如下:

RAC&&MVVM实现一个登录界面和一个分页数据表视图界面

一、RAC中常用的类1.RACSubject

RACSubject是信号RACSignal的一个子类,但它的底部实现与RACSignal有所不同。其订阅信号subscribeNext的方法只是使用nextBlock创建了一个订阅者并保存起来待用,多次调用subscribeNext会保存多个订阅者。只有发送信号sendNext方法执行时,订阅者才会执行nextBlock里的内容,多个订阅者会执行多次

使用示例:

应用示例:替换代理

我们测试这样一个功能:在当前视图控制器A中点击按钮调转到下一视图控制器B,在B的文本框中输入内容,点击编辑完成按钮回到A,显示B中输入的内容到A的UILabel上。通常我们使用代理来解决这样的问题,那么现在我们可以利用RACSubject的特性来代替常用的代理的功能,其实就跟我们使用block回调一样。具体代码如下:

2.RACTuple与RACSequence遍历数组与字典

RACTuple:类似OC的数组,是RAC中用来封装值的元组类,可以配合RACTupleUnpack解元组。

RACSequeue:数组和字典经过rac_sequence方法会被转化为RACSequeue类型,并进一步转为我们常用的信号。订阅此类信号的时候,信号就会被激活并遍历其中的所有值。

使用示例:

3.RACMulticastConnection:处理重复发送消息的问题

RACMulticastConnection用于解决一个信号被多次订阅后,创建信号中的block被重复调用的问题,所以在实际开发中,使用RACMulticastConnection可以解决网络重复请求的问题。

测试1:普通的信号

测试2:使用RACMulticastConnection

4.RACCommand:用于处理事件的类

RACCommand可以把事件如何处理,如何传递都封装到类中,之后就可以方便的调起它的执行方法。在实际开发中,我们可以用它来封装一个网络操作。

注意:

1.创建方法中block返回一个信号,且不能为nil,但是可以使用[RACSignal empty]表示空信号

2.RACCommand必须被强引用,否则容易被释放

二、RAC常用的宏定义

1.RAC(对象,对象属性):绑定属性

输入框背景色绑定了映射后的validUserNameSignal信号,信号变化时背景色更新

2.RACObserve(被观察的对象,被观察对象的属性) :代替KVO监听某个对象的某个属性

3.RACTuplePack与RACTupleUnpack

RACTuplePack:将数据封装成元组

RACTupleUnpack:将元组解包为数据

4.@weakify、@strongify

RAC中使用@weakify、@strongify解决Block循环引用的问题。在block内部使用@strongify(self)后就可以使用self操作属性了,但是一定注意这两个宏定义一定要配合使用,可参考源码分析。

三、RAC中关于信号的常用操作

本节整理了以下几种常用信号操作:

1.信号映射:map与flattenMap

2.信号过滤:filter、ignore、 distinctUntilChanged

3.信号合并: combineLatest、reduce、merge、zipWith

4.信号连接:concat、then

5.信号操作时间:timeout、interval、dely

6.信号取值:take、takeLast、takeUntil、

7.信号跳过:skip

8.信号发送顺序:donext、cocompleted

9.获取信号中的信号:switchToLatest

10.信号错误重试:retry

11.信号节流:throttle

12.信号操作多线程:deliverON、subscribeOn

一、信号映射:map与flattenMap

map:将信号内容修改为另一种新值。改变了传递的值

flattenMap:将源信号映射修改为另一种新的信号。修改了信号本身

1.map

将信号文本值修改为文本长度

2.flattenMap

flattenMap的block返回的是你想要的信号

特别说明:信号中信号常出现在我们封装一个网络请求为信号的时候,这时候注意flattenMap的使用。

二、信号过滤:filter、ignore、 distinctUntilChanged1.filter

过滤信号,符合条件的信号才能发出消息。

示例:输入1234,当输入到4(文本长度大于3)的时候才开始打印如下的信息

2.ignore

忽略信号,针对信号值的某一种状态进行忽略,忽略时不会发送消息。

示例:监听每次的输入,但是当文本框内的内容是"a"时不会打印

3.distinctUntilChanged

当上次的值与当前值有变化时才会发出消息,否则信息被忽略

三、信号合并:combineLatest、reduce、merge、zipWith

为了便于测试,这里先创建两个RACSubject类型的信号用于测试,此类信号只有发送信号sendNext方法执行时,订阅者才会执行nextBlock里的内容;

1. combineLatest:合并信号

合并信号的效果就是,这多个信号都至少有过一次订阅信号sendNext的操作,才会触发合并的信号。下面的测试如果只有signalOne执行sendNext方法,那么combineLatest后的信号不会被触发。

2. reduce:聚合信号

combineLatest合并后的信号订阅后,得到的是一个元组(包含每个被合并信号的新值)。然而在开发中,我们往往需要检测多个信号合并后的效果(比如用户名和密码信号有效时,登录按钮才可以点击),这里就用到了reduce来实现信号聚合。

reduce聚合操作中的block参数个数随合并信号的数量而定,有多少个信号被合并,blcok中的参数就有多少个。这些参数一一对应被合并的信号,是它们对应的新值。

3. merge:合并信号

当合并后的信号被订阅时,就会订阅里面所有的信号

测试1:将多个信号合并之后,当其中任何一个信号发送消息时,都能被监测到。

测试2:当合并后的信号被订阅时,就会订阅里面所有的信号

4. zipWith:压缩信号

1.zipWith把两个信号压缩成为一个信号。

2.只有当两个信号同时发出信号时,两个信号的内容才会被合并为一个元组,触发压缩流的next事件。比如:当一个界面多个请求的时候,要等所有请求完成才更新UI。元组内元素顺序只与压缩信号的顺序有关,与发送信号的顺序无关。

四、信号拼接:concat、then1.concat

1.使用concat可以按序拼接多个信号,拼接后的信号按序执行。

2.使用concat连接信号后,每个信号无需再单独订阅,其内部会按序自动订阅

3.前面的信号必须执行sendCompleted,后面的信号才会被激活

2.then:连接信号

使用then连接信号,上一个信号完成后,才会连接then返回的信号,所以then连接的上一个信号必须使用sendCompleted,否则后续信号无法执行。

then连接的多个信号与concat不同的是:之前的信号会被忽略掉,即订阅信号只会接收到最后一个信号的值

五、信号操作时间:timeout、interval、dely1. interval

创建定时器信号,每固定时间发送一次信号

2.timeout

可以设置超时操作,让一个信号在规定时间之后自动报错

创建信号时不能使用sendCompleted,因为这样的话一旦发送了消息就取消订阅了。

3.delay

延迟发送sendNext

六、信号取值take、takeLast、takeUntil

首先创建一个signal来测试这三个方法:

1.take:从开始共取N次的next值

2.takeLast:从最后共取值N次next的值

3.takeUntil:(RACSignal *)

使用RACSubject类型的信号来测试,直到某个信号执行完成 ,才获取信号

七、信号跳过:skip

使用skip跳过几个信号

八、信号发送顺序:doNext、doCompleted

发送信号前与发送信号后操作:doNext、doCompleted

doNext:在订阅者发送消息sendNext之前执行

doCompleted:在订阅者发送完成sendCompleted之后执行

九、获取信号中的信号:switchToLatest

switchToLatest只能用于信号中的信号(否则崩溃),获取最新发送的信号。

十、信号错误重试:retry

retry:只要失败就重新执行信号

十一、信号节流:throttle

当某个信号发送比较频繁时,可以使用throttle节流,在某一段时间不发送信号内容,过了一段时间获取信号的最新内容发出。

十二、信号关于线程的操作

副作用:关于信号与线程,我们把在创建信号时block中的代码称之为副作用。

deliverON:切换到指定线程中,可用于回到主线中刷新UI,内容传递切换到指定线程中,

subscribeOn:内容传递和副作用都会切换到指定线程中。

deliverOnMainThread:能保证原信号subscribeNext,sendError,sendCompleted都在主线程MainThread中执行。

分析:

测试1:未切换线程,发送消息与接收消息都在异步线程中

测试2:使用deliverON,发送消息还在原来的线程,但是接收消息切换到主线程。

测试2:使用subscribeON,发送消息和接收消息都被切换到了主线程中执行。

四、RAC常用的处理事件响应的方法

1.代替代理的使用

基础篇里已经有一种使用RACSubject替换代理的方法,这里是另一种形式的替换。在视图控制中添加自定义视图CustomView,其上有一按钮testBtn添加了响应方法testBtnClick:。此时可以使用RAC在不使用代理的情况下,在视图控制中监听自定义视图中按钮的点击:

关键方法:rac_signalForSelector

使用说明:

1.通过rac_signalForSelector方法,以按钮响应方法为参数,得到一个信号。

2.订阅信号,在按钮点击时会发出信号。经过测试,即使testBtnClick方法没有在自定义视图的.h文件中声明,执行也是正常的。

2.代替按钮等控制视图的响应事件

创建一个类似按钮的响应控件,我们可以不必再为其添加响应方法。使用RAC可以将按钮点击事件转化为信号,点击按钮会发送信号,执行订阅方法。

关键方法:rac_signalForControlEvents

3.代替KVO,监听对象属性变化

关键方法:rac_valuesAndChangesForKeyPath

使用说明:

1.自定义视图_customView属性frame的变化被转化信号,frame发生变化的时候,会发送信号。

2.observer可以为nil,但是会报警告。

4.监听文本输入变化

关键方法:rac_textSignal

UITextField与UITextView输入视图内容的变化,我们也可以采用RAC的方法来监听

5.代替通知的使用

关键方法:rac_addObserverForName

6.多请求汇总处理

关键方法:rac_liftSelector:withSignals:

五、本篇总结

写到这里,其实RAC还是有好多东西没有在这里涉及,本篇也只是对于它最常用的部分进行了归纳总结,尤其是我对于RAC在MVVM架构中的使用还不太熟练。RAC的学习,这仅仅是一个开始,继续努力吧!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180811G14MM800?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券