6 RAC终结篇
6.1 映射
RAC
的映射主要有两个方法(flattenMap
map
),这两个方法主要用于将信号源的内容映射成为一个新的信号。
-
flattenMap
它其实也是绑定信号,一般用于信号中的信号。
RACSubject *subject = [RACSubject subject];
RACSignal *signal = [subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
value = [NSString stringWithFormat:@"处理数据:%@",value];
//返回信号用来包装修改过的内容
return [RACReturnSignal return:value];
}];
//订阅绑定信号
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送数据
[subject sendNext:@"123"];
运行如图:
image看起来有点绕,说白了我们在什么场景下会用到这种呢?
就在我们发送的数据,需要对数据进行处理然后再订阅这个信号的时候就可以使用这种方式,其实跟我们上一节中提到的
bind
是一样的。
- map
这个方法跟flattenMap
稍微有一点不同,他的block
返回值是一个id
类型,而flattenMap
是一个信号。
也就是说不用在返回信号了,直接返回一个数据,返回的数据就是处理后的数据。
RACSubject *subject = [RACSubject subject];
RACSignal *signal = [subject map:^id _Nullable(id _Nullable value) {
//返回的数据就是需要处理的数据
return [NSString stringWithFormat:@"%@123",value];
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送数据
[subject sendNext:@"我想静静"];
运行如图:
image
6.2 组合
concat:按顺序组合。
刚刚我们说到了rac_liftSelector
的使用场景,它是在等多个信号全部都返回数据后再刷新UI。那么我们现在有一个需求,就是按顺序刷新UI,也就是说你这些接口什么时候请求完数据我并不知道,但是你请求完成后的处理要按照我的顺序来。处理完第一个,再处理第二个。
//组合!!
//创建信号!!
RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送请求A");
//发送数据
[subscriber sendNext:@"数据A"];
//哥么结束了!!
[subscriber sendCompleted];
//[subscriber sendError:nil];
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送请求B");
//发送数据
[subscriber sendNext:@"数据B"];
[subscriber sendCompleted];
return nil;
}];
RACSignal * signalC = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送请求C");
//发送数据
[subscriber sendNext:@"数据C"];
[subscriber sendCompleted];
return nil;
}];
//concat:按顺序组合!!
//创建组合信号!!
RACSignal * concatSignal = [RACSignal concat:@[signalA,signalB,signalC]];
//订阅组合信号
[concatSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
运行如图:
image
then:
忽略掉前面一个信号所有的值,返回后一个信号的数据。也就是说后一个信号的数据要依赖前一个信号的发送完毕,但我并不需要处理前一个信号的数据。
//创建信号!!
RACSignal * signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送请求A");
//发送数据
[subscriber sendNext:@"数据A"];
[subscriber sendCompleted];
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"发送请求B");
//发送数据
[subscriber sendNext:@"数据B"];
[subscriber sendCompleted];
return nil;
}];
//then:忽略掉第一个信号所有的值!!
RACSignal * thenSignal = [signalA then:^RACSignal * _Nonnull{
return signalB;
}];
//订阅信号
[thenSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
运行如图:
image
merge: 无序组合,谁先发送谁先处理。
前面我说到的都是有序的,那么肯定也有无序的组合,假设我们一般页面有N多个接口的请求,需要来一个就显示一个。处理的代码呢也能写到一起。
//创建信号
RACSubject * signalA = [RACSubject subject];
RACSubject * signalB = [RACSubject subject];
RACSubject * signalC = [RACSubject subject];
//组合信号
RACSignal * mergeSignal = [RACSignal merge:@[signalA,signalB,signalC]];
//订阅 -- 根据发送的情况接受数据!!
[mergeSignal subscribeNext:^(id _Nullable x) {
//任意一二信号发送内容就会来这个Block
NSLog(@"%@",x);
}];
//发送数据
[signalC sendNext:@"数据C"];
[signalA sendNext:@"数据A"];
[signalB sendNext:@"数据B"];
运行如图:
image
zipWith:
两个信号压缩!只有当两个信号同时发出信号内容,并且将内容合并成为一个元祖给你
//创建信号
RACSubject * signalA = [RACSubject subject];
RACSubject * signalB = [RACSubject subject];
//压缩
RACSignal * zipSignal = [signalA zipWith:signalB];
//接受数据 和发送顺序无关!!
[zipSignal subscribeNext:^(id _Nullable x) {
RACTupleUnpack(NSString *str1,NSString *str2) = x;
NSLog(@"str1=%@,str2=%@",str1,str2);
}];
//发送数据
//这是一组
[signalB sendNext:@"小明"];
[signalA sendNext:@"小小"];
//这也是一组
[signalB sendNext:@"小明1"];
[signalA sendNext:@"小小1"];
//这也是一组
[signalB sendNext:@"小明2"];
[signalA sendNext:@"小小2"];
运行如图:
image这里 只有
signalA
、signalB
同时发送了一次信号,才会接收到信号,接收到的数据是一个元祖,值就是signalA
、signalB
发送的数据。
元祖的数据顺序和你发送的顺序无关,而是和[signalA zipWith:signalB]
这个方法有关。
combineLatest: reduce:
组合信号,将多个信号的数据进行合并处理,在返回一个数据给新的信号。
这个东西呢,我们我们通过一个例子来说明,就拿一个简单的登录来说把。
首先呢有两个输入框(UITextField
),账号和密码,还有一个按钮(UIButton
),首先这个按钮是不可点击的,当两个输入框都有值的情况下呢按钮才可以点击。
UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
[self.view addSubview:nameTF];
nameTF.placeholder = @"请出入昵称";
nameTF.backgroundColor = [UIColor yellowColor];
UITextField *pwdTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 120, 200, 50)];
[self.view addSubview:pwdTF];
pwdTF.placeholder = @"请出入密码";
pwdTF.backgroundColor = [UIColor grayColor];
UIButton *loginBtn = [[UIButton alloc]initWithFrame:CGRectMake(10, 180, 100, 50)];
[self.view addSubview:loginBtn];
[loginBtn setTitle:@"登录" forState:UIControlStateNormal];
[loginBtn setBackgroundColor:[UIColor purpleColor]];
RACSignal *signalBtn = [loginBtn rac_signalForControlEvents:(UIControlEventTouchUpInside)];
[signalBtn subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//组合
//reduceBlock参数:根据组合的信号关联的 必须一一对应!!
RACSignal * signal = [RACSignal combineLatest:@[nameTF.rac_textSignal,pwdTF.rac_textSignal] reduce:^id _Nullable(NSString *nickName,NSString * pwd){
//两个文本框的text是否有值!!
return @(nickName.length && pwd.length);
}];
RAC(loginBtn,enabled) = signal;
运行如图:
image
6.3 过滤
- filter: 当满足特定的条件,才能获取到订阅的信号数据。
UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
[self.view addSubview:nameTF];
nameTF.backgroundColor = [UIColor yellowColor];
RACSignal *signal = [nameTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
if (value.length > 5) {
return YES;
}
return nil;
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
运行如图:
image
- ignore:忽略掉哪些值。
UITextField *nameTF = [[UITextField alloc]initWithFrame:CGRectMake(10, 64, 200, 50)];
[self.view addSubview:nameTF];
nameTF.backgroundColor = [UIColor yellowColor];
RACSignal *signal = [nameTF.rac_textSignal ignore:@"a"];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
运行如图:
输入第一个a
并没有监听到
- take: 指定拿前面的哪几条数据!!(从前往后)
RACSubject * subject = [RACSubject subject];
//take:指定拿前面的哪几条数据!!(从前往后)
//takeLast:指定拿后面的哪几条数据!!(从后往前)注意点:一定要写结束!!
[[subject take:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"2"];
[subject sendNext:@"3"];
[subject sendNext:@"1"];
[subject sendCompleted];
运行如图:
- takeLast: 指定拿后面的哪几条数据!!(从后往前)注意点:一定要写结束!!
RACSubject * subject = [RACSubject subject];
//take:指定拿前面的哪几条数据!!(从前往后)
//takeLast:指定拿后面的哪几条数据!!(从后往前)注意点:一定要写结束!!
[[subject takeLast:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"2"];
[subject sendNext:@"3"];
[subject sendNext:@"1"];
[subject sendCompleted];
运行如图:
- takeUntil:直到你的标记信号发送数据的时候结束!!!
RACSubject * subject = [RACSubject subject];
//专门做一个标记信号!!
RACSubject * signal = [RACSubject subject];
//takeUntil:直到你的标记信号发送数据的时候结束!!!
[[subject takeUntil:signal] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"2"];
[subject sendNext:@"静静"];
[signal sendNext:@"小明"];//这个信号发送之后就结束了。
// [signal sendCompleted];//标记信号!! 这个信号发送之后也一样结束。
[subject sendNext:@"3"];
[subject sendNext:@"1"];
[subject sendCompleted];
当signal发送信号后,subject的发送就会结束,这里的 3 1 就不会在发送了。这种方式也比较常用。
运行如图:
- distinct:忽略掉重复数据
//1.创建信号
RACSubject * subject = [RACSubject subject];
//忽略掉重复数据
[[subject distinctUntilChanged] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送
[subject sendNext:@"小明"];
[subject sendNext:@"小明"];
[subject sendNext:@"小小"];
[subject sendNext:@"小爱"];
运行如图:
这样可以吧。。我们换个顺序好了
看图:
依旧是两个小明,不太靠谱吧
- skip: 跳跃几个值
RACSubject * subject = [RACSubject subject];
//skip: 跳跃几个值
[[subject skip:2] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[subject sendNext:@"小明"];
[subject sendNext:@"小小"];
[subject sendNext:@"小红帽"];
[subject sendNext:@"小爱"];
[subject sendNext:@"小不点"];
[subject sendNext:@"大灰狼"];
运行如图:
image
网友评论