ReactiveCocoa进阶(2)
2017-09-16 本文已影响7人
攻克乃还_
所有的RACSignal都可以进行操作处理,因为所有的操作方法都定义在Stream.h中,因此只要继承了RACStream就有了操作处理的方法
ReactiveCocoa操作思想:
- Hook(钩子)思想:改变API(应用程序编程接口,也就是方法)执行结果
一、ReactiveCocoa核心方法:bind
- ReactiveCocoa的核心方法是bind(绑定),也是RAC的核心开发方式
- 之前我们用的开发方式是赋值,现在我们创建对象的时候,就绑定好以后要做的事情,而不是等待赋值之后在做事情
- 我们之前展示数据到控件上,都是重写setModel方法,而RAC在一开始创建控件时就绑定好了数据。
- 实际开发中很少用bind方法,因为bind是RAC底层方法,而RAC已经封装了很多其他方法供我们调用
// 需求:每次在文本框的输入后面+sun
[[_textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{
return ^RACSignal *(id value, BOOL *stop){
// 信号一改变,就会执行,并且把值传递过来
NSString *result = [NSString stringWithFormat:@"%@%@",value,@"sun"];
return [RACReturnSignal return:result];
};
}] subscribeNext:^(id _Nullable x) {
NSLog(@"获取到处理完的数据 %@",x);
}];
二、ReactiveCocoa操作方法之映射(flattenMap,map)
- map方法是对于flattenMap方法的封装,flattenMap是对于bind方法的封装,拦截源信号的内容,改变后传出
- map的block的返回值类型为id,flattenMap的block的返回值类型为RACSignal
- 给订阅者发出的值不是信号,一般使用map
- 给订阅者发出的值是信号,一般使用flatternMap
- map的简单使用
[[_textField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
NSString *result = [NSString stringWithFormat:@"xmg %@",value];
return result;
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
- flattenMap的简单使用
[[_textField.rac_textSignal flattenMap:^ RACSignal * (NSString * value) {
NSString *result = [NSString stringWithFormat:@"sun %@",value];
return [RACReturnSignal return:result];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
- 当遇到信号中的信号时,要使用flattenMap,map结合
[[signalOfSignals flattenMap:^RACSignal *(id value) {
return [value map:^id _Nullable(id _Nullable value) {
return [NSString stringWithFormat:@"XMG:%@",value];
}];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"1-%@",x);
}];
三、ReactiveCocoa操作方法之组合
3.1.concat
-
[signalA concat: signalB]
把两个信号合并为一个信号,当signalA的事件完成,才能触发signalB的事件 - 订阅后,先接收到signalA的信息,然后接收到signalB的信息
- 方法内部直接订阅了signalA
- 应用场景: 需要把两次请求的数据添加到一个数组,先添加A, 在添加B
concat语法:
// 创建信号
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACReplaySubject subject];
NSMutableArray *arrM = [NSMutableArray array];
// concat
[[signalA concat: signalB] subscribeNext:^(id _Nullable x) {
[arrM addObject:x];
}];
// 发送信号
[signalB sendNext:@"B"];
[signalA sendNext:@"A"];
[signalA sendCompleted];
3.2.then
- 当 前面一个信号的事件完成,才能触发then后面信号的事件
- 订阅后, 只能接收到后一个信号给订阅者的信息
- 原理:使用concat连接then返回的信号,忽略之前信号发出的信息
then语法:
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}];
[[signalA then:^RACSignal * _Nonnull{
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@2];
return nil;
}];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
3.3.merge
- 把多个信号合并为一个信号, 任何一个信号给订阅者发送信息都能监听到
// 无序的整合信号数据
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
[[signalA merge:signalB] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
// 发送
[signalB sendNext:@"B"];
[signalA sendNext:@"A"];
3.4.zipWith
- 把两个个信号压缩成一个信号,只有当 两个信号都给订阅者发送数据时,才能监听到
- 返回的x为元组
RACSubject *signalA = [RACSubject subject];
RACSubject *signalB = [RACSubject subject];
[[signalA zipWith:signalB] subscribeNext:^(id _Nullable x) {
RACTupleUnpack(NSString *a,NSString *b) = x;
NSLog(@"%@ %@",a,b);
}];
[signalA sendNext:@"A"];
[signalB sendNext:@"B"];
3.5.combineLatest (组合)
- 把两个信号组合成一个信号时,和zip一样
- 把多个信号合并为一个信号,只有当 所有信号都给订阅者发送数据时,才能监听到
- 订阅后,得到的是各个信号的最新值
- 返回的x为元组
[[_accountField.rac_textSignal combineLatestWith:_pwdField.rac_textSignal] subscribeNext:^(id _Nullable x) {
RACTupleUnpack(NSString *account,NSString *pwd) = x;
_loginButton.enabled = account.length > 0 && pwd.length;
}];
3.6.reduce(聚合)
- reduce后的block参数是自己写上去的。有几个信号,就写几个参数,每个参数都是信号给订阅者发送的数据
- 底层实现:订阅聚合信号,每次有内容发出,就会执行reduce的blcok,把信号内容转换成blcok返回的值。
- 把多个信号给订阅者发送的数据聚合到一起
// 常见用法:先组合再聚合
[[RACSignal combineLatest:@[_accountField.rac_textSignal,_pwdField.rac_textSignal]
reduce:^id (NSString *account, NSString *pwd){
//这里返回什么,下面Block的x就是什么
return @(account.length > 0 && pwd.length > 0);
}] subscribeNext:^(id _Nullable x) {
_loginButton.enabled = [x boolValue];
}];
四、ReactiveCocoa核心操作方法-filter(过滤)
- 减少使用if
- 返回YES才可以给订阅者发送数据
[[_pwdField.rac_textSignal filter:^BOOL (NSString *value) {
// 必须要满足这个条件,才可以给订阅者发送数据
return value.length > 6;
}] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@",x);
}];
五、ReactiveCocoa核心操作方法-定时器
interval: onScheduler:
- RACScheduler:多线程,管理多线程
[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]
subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"执行了定时器");
}];
六、ReactiveCocoa核心操作方法-delay(延迟执行)
// 延迟发送数据
[[[RACSignal createSignal:^RACDisposable *(id <RACSubscriber> subscriber) {
[subscriber sendNext:@"hello"];
return nil;
}] delay:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
遵循NSFastEnumeration协议的可以当做数组