前言
应用通常会消费、制造和更新数据。响应式编程是一种编程范式,能够表示数据流,而无需担心副作用或对其他并发执行的任务造成影响。
响应式编程背后的核心思想是随时间流逝体现数据的值。使用动态值的数据流会导致这些值随着时间而变化。
函数响应式编程(functional reactive programming,FRP)允许响应式编程使用内建的块方法进行函数式编程,如map、reduce、filter、merge,等等。
ReactiveCocoa 的灵感来自 FRP。因为多组件的应用以高内聚的方式工作,所以组件状态的使用和更新就有了很强的关联。正因为这一点,创建一个低耦合、高内 聚的响应式系统才显得尤为重要。
现在有下面4个概念:
面向对象编程 Object Oriented Programming
响应式编程 Reactive Programming
函数式编程 Functional Programming
函数响应式编程 Functional Reactive Programming
Reactive Cocoa 是一个重量级框架,非常的牛,为什么说Reactive Cocoa非常的牛?
我们所熟知的iOS 开发中的事件包括:
- Target
- Delegate
- KVO
- 通知
- 时钟
- 网络异步回调
ReactiveCocoa ,就是用信号接管了iOS 中的所有事件;也就意味着,用一种统一的方式来处理iOS中的所有事件,解决了各种分散的事件处理方式,显然这么一个庞大的框架学习起来也会比较难!
从这张图中,可以看出利用信号,ReactiveCocoa接管iOS 的所有事件,抛给开发者对事件作出三个相应反应;
可以用一张图来简要说明
RAC 的特点
下面用iOS开发中常见的五种事件来说明ReactiveCocoa的常见用法!
下载框架:
- 新建iOS工程
- 进入终端,建立 Podfile,并且输入以下内容
在终端输入以下命令安装框架
$ pod install
常见用法
KVO 监听
程序实现: 监控Person name的属性变化;在touchesBegan中改变name的值,并将变化体现在UILabel上,实现KVO的监控功能;
- 注意,RAC 的信号一旦注册不会主动释放
- 只要在 block 中包含有 self. 一定会出现强引用* 需要使用 @weakify(self) / @strongify(self) 组合使用解除强引用
文本框输入事件监听
文本框组合信号
按钮监听
按钮点击后看日志输出
代理方法
通知
viewDidLoad 中添加
高级用法
1. flattenMap
,map
merge
:把多个信号合并成一个信号,只需订阅这一个信号就相当于订阅了多个信号,任何一个信号有新值的时候都会触发调用。
concat
:将多个信号有顺序的连接起来,按照顺序接收信号,但是一定要之前的信号完成了才能发送下一个信号。
then
:用于连接两个信号,内部也是使用concat,当前一个信号完成之后才会连接then返回的信号,但是会忽略前一个信号,只会触发下个信号。
zip
:将对各信号压缩成一个信号,只有当几个信号同时sendNext的时候才会触发压缩流的next事件,其中每一个信号send的内容都是一一对应的。
combineLatest
:将多个信号组合起来,当其中每一个信号都sendNext之后,才会触发组合的信号,其中每一个信号再次sendNext都会覆盖之前的信号内容,返回的是一个RACTuple(元组,类似于NSArray)。
rac_liftSelector: withSignalsFromArray:
:当信号组中每一个信号都至少一次sendNext之后,将触发Selector方法,类似于combineLatest
。
reduceEach
:一般用于元组,把元组的值聚合成一个值。
filter
:过滤信号,添加筛选条件,只有符合的才会触发调用。
distinctUntilChanged
:当前值跟上一次的值不同的时候,就会触发调用,否则被忽略。
take
:从第一个信号开始设置信号发送的有效的个数。
takeLast
:从最后一个开始设置信号发送的有效个数,必须sendCompleted,不然不知道总共多少个信号。
takeUntil
:[signal1 takeUntil:signal2]
,当signal2已经sendNext或者sendCompleted,signal1就会失效。
skip
:跳跃,从第一个发出的信号开始跳。
doNext
:在执行sendNext之前会执行这个。
timeout
:在超过设定时间范围之后让信号报错,且不能发送内容。
interval
:定时,每隔一定时间发出时间信号。
delay
:延时发送信号
retry
:重试,只要失败,就会重新执行创建信号中的block,直到成功。
throttle
:节流,当某个信号发送比较频繁的时候,可以限制在一定之间内不接受信号,等过了这个时间再取最后发送的信号内容发出,类似于bufferWithTime:onScheduler:
。
deliverOn
:内容传递切换到指定线程中,副作用在原来线程中,把在创建信号时block中的代码称之为副作用。
subscribeOn
:内容传递和副作用都会切换到指定线程中。
RACSubject
信号提供者,本身可以充当信号,又能发送信号,继承自RACSignal,但是底层实现跟RACSignal有些不一样,当订阅信号的时候会创建订阅者并保存订阅响应Block,而发送信号的时候会遍历订阅者,然后分别调用nextBlock。它提供的API很少,但是经常使用,因为它继承自RACSignal。这里顺便来看一下方法
flatten
跟switchToLatest
,这两个都只能用来处理信号中的信号。
flatten
:压平信号中的信号,信号中的信号我们称之为子信号,flatten可以拿到所有子信号发送的值。
switchToLatest
:与flatten相同,压平信号中的信号,不同的是,在存在多个子信号时候只会拿到最新的子信号,然后输出最新的子信号的
RACReplaySubject
重复提供信号类,继承自RACSubject,它可以先发送信号,再订阅信号,原理就是 将发送的信号内容保存了起来,当订阅信号的时候再将之前保存的信号,由订阅者一个一个的发送出来,而保存信号的容量由capacity来控制。
方法解析及实现原理
publish
,multicast
:这是对RACMulticastConnection初始化方法的一个封装,publish
其实就是调用了multicast
,并把创建好的RACSubject对象传给它,而multicast
也就是调用了RACMulticastConnection
的初始化方法,将原始信号传给source
,把RACSubject
对象传给subject
。- 当我们订阅connect.signal,其实就是订阅subject,然后将subject的订阅者保存起来,而调用
[connect connect]
的时候,会订阅原始信号(source),而source的订阅者就是subject,这时候subject就会执行[subject sendNext]
,之后就会遍历subject所有的订阅者,逐一发送信号,触发外部subscribeNext回调。
RACCommand
这是一个命令类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程,一般来说是在UI上的某些动作来触发这些事件,比如点击一个按钮,RACCommand的实例能够决定是否可以被执行,一般用于网络请求,监控请求过程。
RACChannel
这是一个通道类,可以理解为一个双向的连接,连接的两端都配有
RACChannelTerminal
(通道终端,继承自RACSignal,且又实现了RACSubscriber协议,所以它可以充当信号,又能发送信号),分别是leadingTerminal
,followingTerminal
,只要其中任何一端输出信号,另一端都会有相同的信号输出。我们平时很少直接使用RACChannel
,而是使用RACChannelTo
。
RACChannelTo
:使用这个宏要传入相关对象以及它的属性,比如RACChannelTo(view,backgroundColor)
,实际上创建了一个RACKVOChannel
对象,在内部将其一端的leadingTerminal
与view的backgroundColor属性进行绑定,并将其另一端followingTerminal
暴露出来,也就是RACChannelTo
的返回值,我们可以对followingTerminal
进行订阅,拿到view. backgroundColor,同样followingTerminal
发送信号也会同步到view.backgroundColor。用它来实现双向绑定,
RACChannelTo(button,backgroundColor) =RACChannelTo(view,backgroundColor);
将button跟view的背景颜色进行绑定,两边相互影响,进行同步。
代码如下:
运行效果:
没有绑定前
绑定后:点击事件未触发
触发点击事件
常用宏
RAC(TARGET,...)
:给某个对象的某个属性进行绑定。
//当textfield开始编辑时,关闭button响应
RAC(_button,enabled) = [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] mapReplace:@NO];
RACObserve(TARGET,KEYPATH)
:KVO,监听某个对象的属性,返回的是信号。
RACChannelTo
:用于双向绑定的一个通道终端。
RACTuplePack
:将数据包装成RACTuple(元组)。
RACTupleUnpack(...)
:把元组解包成对应的数据
demo
https://github.com/kangxg/ThreadLock.git
原文链接:https://www.f2er.com/react/302628.html