序
之前就一直在看ReactiveCocoa 相关知识 但是有感觉每次看完收货甚微,且感觉零零散散 ,本blog 仅仅是记录自己的学习过程
文章目录
- 1 ReactiveCocoa 核心方法Bind
- 2 ReactiveCocoa 之映射(flattenMap,Map)
- 2-1 flattenMap和Map的区别
- 3 ReactiveCocoa 操作方法之组合
- 3-1 concat 按顺序的接受信号
- 3-2 then 用于连接两个信号 当第一个信号完成 才会连接then返回的信号
- 3-3 merge 把多个信号合并成一个信号 任何一个信号有新值的时候就会调用
- 3-4 zipWith 把两个信号压缩成一个信号 只有当两个信号同时发出信号内容时 并且把两个信号的内容合并成一个元祖 才会触发压缩流的next事件
- 3-5 combineLatest 将多个信号合并起来 并且拿到各个信号的最新的值 必须每个合并的signal至少都有过一次sendNext 才会触发合并的信号 和zipwith 差不多
- 3-6 reduce(减少,降低 ,归纳) 聚合 用于信号发出的内容是元祖 把信号发出元祖的值聚合成一个值 然后通过reduce返回出来
- 4 ReactiveCocoa 操作方法之过滤
- 4-1 filter: 过滤信号 使用他可以获取满足条件的信号
- 4-2 ignore 忽略某些值 的信号
- 4-3 distinctUntilChanged 当上一次的值和当前的值不一样才会发出信号 如果两次的值一样 就不会发出信号
- 4-4 take 取出信号 取出前几个信号
- 4-5 takeLast 取最后N次的信号 前提条件订阅者必须调用完成 因为只有完成才知道总共有多少个信号
- 4-6 takeUntil(RACSignal *)获取信号直到某个信号执行完成
- 4-7 skip:(NSUInteger):跳过几个信号 不接收
- 5 ReactiveCocoa 操作方法之秩序
- 5-1 doNext 执行next之前会先执行这个block
- 5-2 doComplete 执行sendComplete就会调用这个方法
- 6 ReactiveCocoa 操作方法之时间
- timeout: 超时 可以让一个信号在一定的时间后 自动报错
- interval: 定时 每隔一段时间就发出信号
- delay 延迟发送next
- 7 ReactiveCocoa 操作方法之重复
- retry 重试 只要失败 就一直执行信号中的block 直到成功
- replay 重放 当一个信号被多次订阅 反复播放内容(没什么卵用)
一 ReactiveCocoa常见操作方法介绍
1.1 ReactiveCocoa 核心方法Bind
ReactiveCocoa操作的核心方法是bind(绑定),而且RAC中核心开发方式,也是绑定,之前的开发方式是赋值,而用RAC开发,应该把重心放在绑定,也就是可以在创建一个对象的时候,就绑定好以后想要做的事情,而不是等赋值之后在去做事情。
列如:把数据展示到控件上,之前都是重写控件的setModel方法,用RAC就可以在一开始创建控件的时候,就绑定好数据。
在开发中很少使用bind方法,bind属于RAC中的底层方法,RAC已经封装了很多好用的其他方法,底层都是调用bind,用法比bind简单.
bind 方法简单的介绍和使用
// 拼接内容
// 方式一 拿到结果后拼接内容
[self.textFiled.rac_textSignal subscribeNext:^(id x) {
NSLog(@"内容:%@",x);
}];
// 方式二 拿到结果之前 进行拼接 利用Bind方法处理
// 处理原有信号 对信号进行加工
// bind 方法参数 需要传入一个返回值是 RACStreamBindBlock 的参数
// RACStreamBindBlock 是一个block类型 返回值是信号 参数是value和stop 因此参数block返回值也是一个block
// RACStreamBindBlock
// value 表示接收到信号的原始值 还没做处理
// *stop 用来控制绑定block 如果 *stop = yes 那么就会结束绑定
// 返回值: 信号 做好处理 在通过这个信号返回出去 一般使用RACreturnsignal,需要手动导入头文件RACReturnSignal.h
// bind方法使用步骤:
// 1 传入一个返回值为 RACStreamBindBlock 的bindblock
// 2 描述一个RACStreamBindBlock 类型的bindblock作为block的返回值
// 3 描述一个返回结果的信号 作为bindblock的返回值
// 在bindblock中做信号结果的处理
// 底层实现:
// 1 源信号调用bind,会重新创建一个绑定信号。
// 2 当绑定信号被订阅,就会调用绑定信号中的didSubscribe,生成一个bindingBlock。
// 3 当源信号有内容发出,就会把内容传递到bindingBlock处理,调用bindingBlock(value,stop)
// 4 调用bindingBlock(value,stop),会返回一个内容处理完成的信号(RACReturnSignal)。
// 5 订阅RACReturnSignal,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
[[self.textFiled.rac_textSignal bind:^RACStreamBindBlock{
return ^RACStream *(id value,BOOL *stop){
return [RACReturnSignal return:[NSString stringWithFormat:@"输出%@",value]];
};
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.2 映射(flattenMap,Map)
- 这两者主要是把源信号 内容映射成新的内容
---- flattenMap : 把原信号的内容映射成一个新信号 信号可以是任意的类型
// flattenMap使用步骤:
// 1.传入一个block,block类型是返回值RACStream,参数value
// 2.参数value就是源信号的内容,拿到源信号的内容做处理
// 3.包装成RACReturnSignal信号,返回出去。
[[self.textFiled.rac_textSignal flattenMap:^RACStream *(id value) {
// 原信号发出的时候就会调用block
// block作用 : 改变原信号的内容
// 返回值 绑定信号的内容
return [RACReturnSignal return:[NSString stringWithFormat:@"内容%@",value]];
}]subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
---- map: 把原信号的值映射成一个新值
// map 的使用步骤
// 1 传入一个block 类型是返回对象 参数是value
// 2 value就是原信号的内容 直接拿到原信号的内容做处理
// 3 吧处理好的内容直接返回就好了 不用包装成信号 返回的值就是映射的值
[[self.textFiled.rac_textSignal map:^id(id value) {
return [NSString stringWithFormat:@"内容:%@",value];
}]subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
FlatternMap 和 Map的区别
1 FlatternMap 中的block返回的是信号
2 Map中的block返回对象
3 开发中,如果信号发出的值不是信号 映射一般使用Map
4 开发中 如果信号发出的是信号 映射一般使用FlatternMap
signalOfSignals 信号的信号 用FlatternMap
RACSubject *signalOfsignals = [RACSubject subject];
RACSubject *signal = [RACSubject subject];
[[signalOfsignals flattenMap:^RACStream *(id value) {
// 当signalOfsignal 的signal发发出信号才会调用
NSLog(@"拦截%@",value);
return value;
}] subscribeNext:^(id x) {
NSLog(@"内容%@",x);
}];
// 信号的信号发送信号
[signalOfsignals sendNext:signal];
[signal sendNext:@"奥卡姆剃须刀"];
1.3 ReactiveCocoa 操作方法值组合
-
concat 按一定顺序拼接信号 当多个信号发出的时候有顺序的接受信号
// 按一定顺序拼接信号 当多个信号发出的时候有顺序的接受信号
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是一号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是二号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *concatSignal = [signal2 concat:signal1];
// 只有第一个信号完成后 才会执行第二个信号
[concatSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
then 用于连接两个信号 当第一个信号完成 才会连接then返回的信号
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是信号"];
// 只有当第一个信号完成后 第二个信号才会执行
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [oneSignal then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第二个的信号"];
[subscriber sendCompleted];
return nil;
}];
}];
// 订阅第一个信号
[oneSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 订阅第二个信号 只有第一个信号完成后 第二个信号发挥被触发
[twoSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
merge 把多个信号合并成一个信号 任何一个信号有新值的时候就会调用
// 底层实现:
// 1.合并信号被订阅的时候,就会遍历所有信号,并且发出这些信号。
// 2.每发出一个信号,这个信号就会被订阅
// 3.也就是合并信号一被订阅,就会订阅里面所有的信号。
// 4.只要有一个信号被发出就会被监听。
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第一个信号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第二个的信号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *mergeSignal = [oneSignal merge:twoSignal];
[mergeSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
zipWith 把两个信号压缩成一个信号 只有当两个信号同时发出信号内容时 并且把两个信号的内容合并成一个元祖 才会触发压缩流的next事件
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第一个信号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第二个的信号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *zipSignal = [oneSignal zipWith:twoSignal];
// 合并出来是元祖 要想拿到元祖 要对元祖进行解包
[zipSignal subscribeNext:^(id x) {
RACTupleUnpack(id data1,id data2) = x;
NSLog(@"%@---%@",data1,data2);
}];
-
combineLatest 将多个信号合并起来 并且拿到各个信号的最新的值 必须每个合并的signal至少都有过一次sendNext 才会触发合并的信号 和zipwith 差不多
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第一个信号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第二个的信号"];
[subscriber sendCompleted];
return nil;
}];
// 必须两个都发信号 才会触发合并信号 和zipWith 一样没什么区别 也是会组装成元祖
RACSignal *combineSignal = [oneSignal combineLatestWith:twoSignal];
[combineSignal subscribeNext:^(id x) {
RACTupleUnpack(id data1,id data2) = x;
NSLog(@"%@--%@",data1,data2);
}];
-
reduce(减少,降低 ,归纳) 聚合 用于信号发出的内容是元祖 把信号发出元祖的值聚合成一个值 然后通过reduce返回出来
RACSignal *oneSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第一个信号"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *twoSignal = [RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是第二个的信号"];
[subscriber sendCompleted];
return nil;
}];
// 聚合
// 常见的用法 (先组合在聚合)
// combineLatee里边有多少个参数组合 后边的reduce就应该有多少个参数
// reduce 返回值是聚合之后的内容
RACSignal *reduceSignal = [RACSignal combineLatest:@[oneSignal,twoSignal] reduce:^id(NSString *data1,NSString *data2){
return [NSString stringWithFormat:@"我是数据一%@---我是数据二%@",data1,data2];
}];
[reduceSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.4 ReactiveCocoa 操作方法之过滤
-
filter: 过滤信号 使用他可以获取满足条件的信号
RACSignal *newSignal = [self.textFiled.rac_textSignal filter:^BOOL(NSString * value) {
return value.length > 3;
}];
// 只有长度大于三的字符串才能被打印粗来
[newSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
ignore 忽略某些值 的信号
// 只能忽略相等的值 其他的都忽略不了 内部调用的是filter过滤
[[self.textFiled.rac_textSignal ignore:@"123"] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
distinctUntilChanged 当上一次的值和当前的值不一样才会发出信号 如果两次的值一样 就不会发出信号
// 只有两次数据不一样才会触发信号
[[_textFiled.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
take 取出信号 取出前几个信号
// 1 创建信号
RACSubject *signal = [RACSubject subject];
// 2 处理信号 订阅信号的个数 如果订阅一个 只会接受第一个信号 subject 可以先订阅信号 在发送信号
[[signal take:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal sendNext:@"1"];
[signal sendNext:@"2"];
-
takeLast 取最后N次的信号 前提条件订阅者必须调用完成 因为只有完成才知道总共有多少个信号
RACSubject *signal = [RACSubject subject];
// 取最后n次的信号
[[signal takeLast:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal sendNext:@"1"];
[signal sendNext:@"2"];
[signal sendNext:@"3"];
[signal sendNext:@"4"];
// 必须调用完成 只用调用完成才能知道总共的信号量
[signal sendCompleted];
-
takeUntil(RACSignal *)获取信号直到某个信号执行完成
// 创建一个信号
RACSignal *deallocSignal = [self rac_signalForSelector:@selector(viewWillDisappear:)];
// 当deallocSignal信号发送的时候 就会移除通知
[[[[NSNotificationCenter defaultCenter]rac_addObserverForName:UIKeyboardWillShowNotification object:nil] takeUntil:deallocSignal] subscribeNext:^(id x) {
NSLog(@"键盘弹出%@",x);
}];
-
skip:(NSUInteger):跳过几个信号 不接收
RACSubject *signal = [RACSubject subject];
// 只会接收第二个信号
[[signal skip:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal sendNext:@"我是信号一"];
[signal sendNext:@"我是信号二"];
1.5 ReactiveCocoa 操作方法之秩序
-
doNext 执行next之前会先执行这个block
-
doComplete 执行sendComplete就会调用这个方法
[[[[RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"我是奥卡姆剃须刀"];
[subscriber sendCompleted];
return nil;
// 在执行订阅信号之前 会先执行这个方法
}]doNext:^(id x) {
NSLog(@"doNext--%@",x);
// 信号完成后会调用这个方法
}]doCompleted:^{
NSLog(@"完成");
// 订阅信号
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.6 ReactiveCocoa 操作方法之时间
-
timeout: 超时 可以让一个信号在一定的时间后 自动报错
[[[RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"123"];
return nil;
// 报错的时间是3秒
}] timeout:3 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"subscribeNext-%@",x);
// 3秒后 自动报错
} error:^(NSError *error) {
NSLog(@"error-%@",error);
}];
-
interval: 定时 每隔一段时间就发出信号
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
-
delay 延迟发送next
[[[RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"延迟两秒钟"];
return nil;
}] delay:2] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
1.7 ReactiveCocoa 操作方法之重复
-
retry 重试 只要失败 就一直执行信号中的block 直到成功
__block int i = 0;
[[[RACSignal createSignal:^RACDisposable *(id subscriber) {
if (i == 10) {
[subscriber sendNext:@"123"];
}else{
[subscriber sendError:nil];
}
i++;
return nil;
}] retry ] subscribeNext:^(id x) {
NSLog(@"subscribeNext--%@",x);
}error:^(NSError *error) {
NSLog(@"error--%@",error);
}];
-
replay 重放 当一个信号被多次订阅 反复播放内容(没什么卵用)
RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id subscriber) {
[subscriber sendNext:@"123"];
[subscriber sendNext:@"456"];
return nil;
}]replay];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];