Hook是一种用于改变API执行结果的技术,而RAC运用的是Hook思想
RAC常见操作介绍
RAC操作需知
所有的信号RACSignal
都可以进行操作处理,因为所有操作方法都定义在RACStream.h
中,因此只要继承RACStream
就有了操作处理方法。
RAC操作思想
运用的是Hook(钩子)思想,Hook是一种用于改变API执行结果的技术
Hook用处:截获API调用的技术
Hook原理:在每次调用一个API返回结果之前,先执行你自己的方法,改变结果的输出
高级操作
核心方法bind
RAC中核心开发方式是绑定
,之前的开发方式是赋值
,用RAC开发,应该把重心放在绑定,也就是可以创建一个对象的时候,就绑定好以后想要做的事情,而不是赋值之后再去做事情
开发中很少用到bind方法,bind属于RAC中的底层方法,RAC已经封装了很多好用的其它方法,底层都是调用bind,用法比bind简单。
bind方法简单介绍和使用
需求:监听文本框的内容,每次输出的时候,在内容后面拼上字符串“jun”,并显示在label上
方式一: 在返回结果后, 拼接字符串
1 2 3 4 5
| @weakify(self) [_textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) { @strongify(self) self.showLabel.text = [NSString stringWithFormat:@"%@+%@", x, @"jun"]; }];
|
方式二: 在返回结果前, 拼接字符串, 用bind方法操作
1 2 3 4 5 6 7 8
| [[_textField.rac_textSignal bind:^RACSignalBindBlock _Nonnull{ return ^RACSignal *(id value, BOOL *stop){ return [RACReturnSignal return:[NSString stringWithFormat:@"输出: %@", value]]; }; }] subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }];
|
- bind 底层实现
源信号调用bind,会重新创建一个绑定信号
当绑定信号被订阅,就会调用绑定信号中的didSubscribe,生成一个bindingBlock
当源信号有内容发出,就会把内容传递到bindingBlock处理,调用bindingBlock(value,stop)
调用bindingBlock(value,stop)会返回一个内容处理完成的信号RACReturnSignal
订阅RACReturnSignal,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
映射(flattenMap,Map)
flattenMap
flattenMap把源信号的内容映射成一个新的信号,信号可以是任意类型
eg:
1 2 3 4 5 6 7 8 9 10 11
| @weakify(self) [[_textField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) { return [RACReturnSignal return:[NSString stringWithFormat:@"flat输出: %@", value]]; }] subscribeNext:^(id _Nullable x) { @strongify(self) self.showLabel.text = x; NSLog(@"%@", x); }];
|
Map
Map作用:把源信号的值映射成一个新的值
eg:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| [[_textField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) { return [NSString stringWithFormat:@"map输出: %@", value]; }] subscribeNext:^(id _Nullable x) { @strongify(self) self.showLabel.text = x; NSLog(@"%@", x); }]; NSArray *arr = @[@"2", @"3", @"a", @"g"]; RACSequence *sequence = [arr.rac_sequence map:^id _Nullable(id _Nullable value) { return [NSString stringWithFormat:@"-%@-", value]; }]; NSLog(@"%@", [sequence array]);
|
组合
concat
按照某一固定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号
eg
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| - (void)setConcatAction { RACSubject *subC = [RACSubject subject]; RACSubject *subD = [RACReplaySubject subject]; NSMutableArray *array2 = [NSMutableArray array]; [[subC concat:subD] subscribeNext:^(id _Nullable x) { [array2 addObject:x]; }]; [subD sendNext:@"D"]; [subC sendNext:@"C"]; [subC sendCompleted]; NSLog(@"%@", array2); }
|
then
用于连接两个信号,当第一个信号完成,才会连接then返回的信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| - (void)setThenAction { RACSubject *subjectA = [RACReplaySubject subject]; RACSubject *subjectB = [RACReplaySubject subject]; [subjectA sendNext:@"A"]; [subjectA sendCompleted]; [subjectB sendNext:@"B"]; [[subjectA then:^RACSignal * _Nonnull{ return subjectB; }] subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; }
|
merge
把多个信号合并为一个信号,任何一个信号有新值的时候就会调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| - (void)setMergeAction { RACSubject *subjectA = [RACSubject subject]; RACSubject *subjectB = [RACSubject subject]; RACSubject *subjectC = [RACSubject subject];
RACSignal *single = [[subjectA merge:subjectB] merge:subjectC]; [single subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; [subjectA sendNext:@"A"]; [subjectC sendNext:@"C"]; [subjectB sendNext:@"B"]; }
|
zipWith
把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| - (void)setZipwithAction { RACSubject *subjectA = [RACSubject subject]; RACSubject *subjectB = [RACSubject subject]; RACSignal *single = [subjectA zipWith:subjectB]; [single subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; [subjectA sendNext:@"A"]; [subjectB sendNext:@"B"];
}
|
combineLatest
将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的信号至少都有过一次sendNext,才会触发合并的信号
1 2 3 4 5 6 7 8 9 10
| - (void)setCombineLatest { RACSignal *single = [_accountText.rac_textSignal combineLatestWith:_passwordText.rac_textSignal]; [single subscribeNext:^(id _Nullable x) { RACTupleUnpack(NSString *account, NSString *password) = x; _loginButton.enabled = account.length > 0 && password.length > 0; }]; }
|
reduce
聚合:用于信号发出是元组的内容,把信号发出元组的值聚合成一个值
1 2 3 4 5 6 7 8 9 10
| - (void)setReduceAction { RACSignal *single = [RACSignal combineLatest:@[_accountText.rac_textSignal, _passwordText.rac_textSignal] reduce:^id (NSString *account, NSString *password){ return @(account.length > 0 && password.length > 0); }]; [single subscribeNext:^(id _Nullable x) { _loginButton.enabled = [x boolValue]; }]; }
|
这里用一个宏, 急需将上面的代码简化一下
1 2 3 4 5
| - (void)setReduceAction { RAC(_loginButton, enabled) = [RACSignal combineLatest:@[_accountText.rac_textSignal, _passwordText.rac_textSignal] reduce:^id (NSString *account, NSString *password){ return @(account.length > 0 && password.length > 0); }]; }
|
过滤
filter
过滤信号, 过滤掉不符合条件的信号
1 2 3 4 5 6 7 8 9 10 11
| - (void) filterAction{ [[_accountText.rac_textSignal filter:^BOOL(NSString * _Nullable value) { return value.length == 11; }]subscribeNext:^(NSString * _Nullable x) { NSLog(@"filter = %@", x); }]; }
|
ignore
忽略掉某些特定值的信号
1 2 3 4 5 6 7 8 9 10 11 12
| - (void)setIgnoreAction { [[_accountText.rac_textSignal ignore:@"m"] subscribeNext:^(NSString * _Nullable x) { NSLog(@"ignore = %@", x); }]; [[_passwordText.rac_textSignal ignoreValues] subscribeNext:^(id _Nullable x) { NSLog(@"allIgnore = %@", x); }]; }
|
distinctUntilChanged
当上一次的值和当前的值有明显的变化就会发出信号,否则会被忽略掉。在开发中,刷新UI经常使用,只有两次数据不一样才需要刷新
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| - (void)setdistinctUntilChanged { RACSubject *subject = [RACSubject subject];
[[subject distinctUntilChanged] subscribeNext:^(id _Nullable x) { NSLog(@"distinctUntilChanged = %@", x); }]; [subject sendNext:@12]; [subject sendNext:@12]; [subject sendNext:@23];
}
|
take
从开始一共取N次的信号, 当遇到sendCompleted语句执行时, 会提前停止发送信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| - (void)setTakeAndTakeLast { RACSubject *subject1 = [RACSubject subject]; [[subject1 take:2] subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; [subject1 sendNext:@1]; [subject1 sendNext:@2]; [subject1 sendCompleted]; [subject1 sendNext:@3]; }
[subject1 sendNext:@1]; [subject1 sendCompleted]; [subject1 sendNext:@2]; [subject1 sendNext:@3];
|
takeLast
取调用sendCompleted之前的N次信号,前提条件,订阅者必须调用sendCompleted,否则不会执行任何操作
1 2 3 4 5 6 7 8 9 10 11 12
| - (void)setTakeAndTakeLast { RACSubject *subject1 = [RACSubject subject]; [[subject1 takeLast:2] subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; [subject1 sendNext:@1]; [subject1 sendNext:@2]; [subject1 sendNext:@3]; [subject1 sendCompleted]; }
|
takeUntil
只要传入的信号发送完成或者subject2开始发送信号的时候,就不会再接收信号的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| - (void)setTakeAndTakeLast { RACSubject *subject1 = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject]; [[subject1 takeUntil:subject2] subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; [subject1 sendNext:@11]; [subject1 sendNext:@12];
[subject1 sendNext:@13]; [subject2 sendNext:@"21"]; [subject2 sendNext:@"22"]; }
|
switchToLatest
主要用于信号的信号, 有时候也会发出信号, 会在信号的信号中获取其发送的最新的信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| - (void)setswitchToLatest { RACSubject *subject1 = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject];
[[subject1 switchToLatest] subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; [subject1 sendNext:subject2]; [subject2 sendNext:@"信号中信号"]; }
|
skip
跳过N个信号后, 再开始订阅信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| - (void)setSkipAction { RACSubject *subject = [RACSubject subject]; [[subject skip:2] subscribeNext:^(id _Nullable x) { NSLog(@"%@", x); }]; [subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3]; [subject sendNext:@4]; }
|
参考
1.ReactiveCocoa 的一些高级用法