bind 绑定/包装
bind 主要作用属于包装,将信号返回的值包装成一个新的值,然后在通过信号返回给订阅者。
- 传入一个返回值 RACSignalBindBlock 的 block
- 描述一个 RACSignalBindBlock 类型的 bindBlock 作为 block 的返回值
- 描述一个返回结果的信号,作为 bindBlock 的返回值,注意在 bindBlock 中做信号结果的处理
1 | [[self.textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull { |
distinctUntilChanged 对比上一次信号内容
实现是用 bind 来完成的,每次变换中都记录一下原信号上一次发送过来的值,并与这一次进行比较,如果是相同的值,就“吞掉”,返回 empty 信号,只有和原信号上一次发送的值不同才会变换成新信号把这个值发送出去。
1 |
|
flattenMap & map 映射
flattenMap 和 map 都是用于把源信号内容映射成新的内容
flattenMap 的底层实现是通过 bind 实现的
map 的底层实现是通过 flattenMap 实现的
flattenMap 使用步骤:
- 传入一个block,block 类型是返回值 RACStream,参数 value;
- 参数 value 就是源信号的内容,拿到源信号的内容做处理;
- 包装成 RACReturnSignal 信号,返回出去。
1 | [[_textField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) { |
map 使用步骤:
- 传入一个 block,类型是返回对象,参数是 value;
- value 就是源信号的内容,直接拿到源信号的内容做处理;
- 把处理好的内容,直接返回就好了,不用包装成信号,返回的值,就是映射的值。
1 |
|
flattenMap & map 区别
- flattenMap 中的 block 返回的是信号
- map 中的 block 返回的是对象
- 开发中,如果信号发出的值不是信号,映射一般使用 map
- 开发中,如果信号发出的值是信号,映射一般使用 flattenMap
concat 合并,有顺序的处理多个信号
按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号
1 |
|
第一个信号必须发送完成,第二个信号才会被激活。
then 下一个
用于连接两个信号,当第一个信号完成后,才会连接 then 返回的信号
底层实现
- 使用 concat 连接 then 返回的信号
- 先过滤掉之前的信号发出的值
1 |
|
会过滤掉第一个 “test1”,只接收第二个信号发送过来的值。
merge 合并,合成一个信号
把多个信号合并为一个信号,任何一个信号有新值的时候就会调用,没有先后顺序,依赖关系(和 concat 的区别)
1 |
|
注意:只要有一个信号被发出就会被监听
combineLatest 结合
将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的 signal 至少都有一次 sendNext,才会触发合并的信号。
1 |
|
reduce 聚合
用于信号发出的内容是元组,把信号发出元组的值聚合成一个值,一般都是先组合在聚合。
1 |
|
filter 过滤
过滤信号,获取满足条件的信号
获取到位数大于 6 的值
1 |
|
ignore 忽略
忽略掉指定的值
忽略掉值为 “999” 的信号
1 |
|
interval 定时
每隔一段时间发出信号
类似于 NSTimer
每隔 1 秒发送一次信号
1 |
|
delay 延迟
延迟执行,类似于 GCD 的 after。
下面例子主要是延迟发送 next
1 |
|
延迟 2 秒后收到 信号 @”delay signalA”
take 取信号
从开始一共取 N 次的信号发送(0 - (N-1))
1 |
|
skip 跳过
从开始一共跳过 N 次的信号发送,只接受之后的信号
1 |
|
takeUntil 获取信号当某个信号执行完成就停止订阅
1 |
|
takeLast 获取最后 N 次的信号
前提条件:订阅者必须调用完成,因为只有完成,才知道总共有多少个信号。
1 |
|
switchToLatest
获取信号中信号最近发出信号,订阅最近发出的信号。
注意:switchToLatest 使用的对象是信号中的信号(signalOfsignals),即 sendNext 的参数也是信号。
1 |
|
doNext
执行 next 之前,会先执行这个 block
1 |
|
doCompleted
执行 sendCompleted 之前,会先执行这个Block。
详细例子见上面 doNext
timeout 超时
如果一个信号在指定时间内没有发送信号,就会超时,可以让一个信号在一定的时间后,自动报错。
1 |
|
retry 重试 或 retry:count
重试,只要失败,就会重新执行创建信号中的 block,一直重试,直到成功。
如果后面指定次数,就会在相应的次数之后结束。
1 |
|
注意上面代码中的注释,必须要发送一个 error 信号的,并且要知道他是错误重试,如果不发生错误就不会重试的。
replay 反复播放(不是重新触发执行)
多个订阅者,只执行一遍副作用,如果没有 replay 就要重复执行副作用。
1 |
|
从上面的打印可以看出来:
- 使用 replay 之后,就像是一个镜像一样了,之后的订阅都是在重复播放之前的镜像,所以外面的副作用 count 的值不会在继续增长。
- 不使用 replay 的话,那么下面的每一次的订阅都会重新触发一次发送信号,副作用 count 的值就会持续增长。
repeat 无限循环的重复执行
1 |
|
由于使用 delay:1.0,所以会每隔 1 秒打印一次,如果不使用将会没有间隔的重复打印。
throttle 节流
当某个信号发送比较频繁时,可以使用节流,在某一段时间差不发送信号内容,过一段时间差后获取信号最新发出的内容,常用场景:
- 阻止 “快速点击” 重复响应等问题。
- 输入框内容不是一变化就请求后台(后台扛不住),可以延迟一会在请求或者输入很快可以让其快速只响应最终的结果。
1 |
|
打印输出:
1 |
|
分析:
- signalA 和 signalB 之间间隔不足 0.5 秒,但是 signalB 与 signalC 间隔超过 0.5 秒,所以先打印 signalB。
- signalC 和 signalD 之间间隔超过 0.5 秒,所以会打印 signalC。
- signalD 和 signalE 之间间隔超过 0.5 秒,所以会打印 signalD。
- signalE 之后没有了,所以会打印 signalE。
zip
给定一个信号数组 signal_array[N],创建一个信号 zip_return,当订阅 zip_return 时,会等待 signal_array 中每一个信号都 sendNext:value 后,zip_return 才会 sendNext,zip_return 传出的值是 [value1, value2, ……, valueN];
1 | RACSignal *signalA = [RACSignal createSignal: |
可以看出来,他其实是 zipWith 的加强版本。
zipWith
两个信号压缩!要两个信号都发出信号,会将其内容合并成一个元组给你,然后下一次触发条件依然是两个信号都有发送。
1 |
|
startWith
在发送消息之前,先发送一个消息。
1 |
|