1.UIKit
监听文本框输入
#UITextField创建了一个 `textSignal`的信号,并订阅了该信号
#当UITextField的内容发生改变时,就会回调subscribeNext
[textField.rac_textSignal subscribeNext:^(id x) {
self.textLabel.text = x;
}];
RAC(self.textlabel,text) = textField.rac_textSignal;
监听的事件
[[textField rac_signalForControlEvents:UIControlEventEditingChanged] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"点击事件%@",x);
}];
[[self.red rac_signalForSelector:@selector(touchesBegan:withEvent:)] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"控制器知道RedView被点击了");
}];
2. Interval定时器
程序进入后台,再重新进入前台时,仍然有效,内部是用GCD实现的
#创建一个定时器,间隔1s,在主线程中运行
@weakify(self)
[[_btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self)
x.enabled = false;
self.time = 10;
#RAC中的GCD
self.dispoable = [[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
_time --;
NSString * title = _time > 0 ? [NSString stringWithFormat:@"请等待 %d 秒后重试",_time] : @"发送验证码";
[self.btn setTitle:title forState:UIControlStateNormal | UIControlStateDisabled];
self.btn.enabled = (_time==0)? YES : NO;
if (_time == 0) {
[self.dispoable dispose];
}
}];
}];
3. 遍历
#遍历数组
NSArray *arr = @[@"11",@"3",@"4"];
[arr.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
#遍历字典
NSDictionary *dic = @{@"a":@"1",@"b":@"2"};
[dic.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"%@==%@",key,value);
}];
[dic.rac_keySequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
[dic.rac_valueSequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
把集合转换成数组
NSArray *arr = @[@1,@2,@3,@4,@4];
NSArray *array = [[arr.rac_sequence map:^id _Nullable(NSNumber * value) {
if (value.integerValue > 2) {
return @2;
}else{
return @3;
}
}] array];
4.KVO / 通知
#通知中心
#当dealloc信号发出的时候 就释放通知
[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"%@ 键盘弹起", x); // x 是通知对象
}];
[[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] takeUntil:[self rac_willDeallocSignal]] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"NotificationCenter %@",x);
}];
#方法1
[redView rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
NSLog(@"%@",value);
}];
#方法2
[[redView rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
#方法3
[[redView rac_valuesForKeyPath:@"frame" observer:nil] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
#方法4
[RACObserve(self.view, center) subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
# 方法1在值发生变化时才执行
# 方法2,3,4 在程序运行时就会被执行
5. RAC 事件绑定
RAC(TARGET, ...)这个宏定义是将对象的属性变化信号与其他信号关联,比如:登录时,当手机号码输入框的文本内容长度为11位时,"发送验证码" 的按钮才可以点击
#当UITextField输入的内容为@"666"时,bView视图的背景颜色变为grayColor
RAC(self.bView, backgroundColor) = [self.textField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
return [value isEqualToString:@"666"]?[UIColor grayColor]:[UIColor orangeColor];
}];
RAC(对象,对象的属性) = (一个信号);
6. rac_liftSelector
当一个界面中有多次请求时,需要保证全部都请求完成,才搭建(刷新)界面,这时需要用到该方法
- (void)rac_liftSelectorTest {
RACSignal *firstSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"模拟第一个网络请求");
[subscriber sendNext:@"第一次获取到的网络数据"];
return nil;
}];
RACSignal *secondSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"模拟第二个网络请求");
[subscriber sendNext:@"第二次获取到的网络数据"];
return nil;
}];
RACSignal *thirdSignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
NSLog(@"模拟第三个网络请求");
[subscriber sendNext:@"第三次获取到的网络数据"];
return nil;
}];
// 方法updateUIWithData1...的参数,对应每个信号发送的数据
[self rac_liftSelector:@selector(updateUIWithData1:Data2:Data3:) withSignalsFromArray:@[firstSignal, secondSignal, thirdSignal]];
}
/// 监听多个模块全部执行完成
/// 方法的参数必须与监听的信号一一对应
/// 方法的参数就是每个信号发送的数据
/// @param data1 对应上面firstSignal 监听的信号发送的数据
/// @param data2 对应上面secondSignal 监听的信号发送的数据
/// @param data3 对应上面thirdSignal 监听的信号发送的数据
- (void)updateUIWithData1:(NSString *)data1 Data2:(NSString *)data2 Data3:(NSString *)data3 {
NSLog(@"更新UI:%@-%@-%@", data1, data2, data3);
}
2021-08-19 10:49:55.569808+0800 RAC[22375:2854756] 模拟第一个网络请求
2021-08-19 10:49:55.570144+0800 RAC[22375:2854756] 模拟第二个网络请求
2021-08-19 10:49:55.570290+0800 RAC[22375:2854756] 模拟第三个网络请求
2021-08-19 10:49:55.570463+0800 RAC[22375:2854756] 更新UI:第一次获取到的网络数据-第二次获取到的网络数据-第三次获取到的网络数据
7. RACMulticastConnection
当一个信号被多次订阅,为避免多次调用创建信号中的block,
使用RACMulticastConnection 链接类
RACSignal * signal =
[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"发送网络请求");
[subscriber sendNext:@"得到网络请求数据"];
return nil;
}];
RACMulticastConnection *connect = [signal publish];
[connect.signal subscribeNext:^(id x) {
NSLog(@"1 - %@",x);
}];
[connect.signal subscribeNext:^(id x) {
NSLog(@"2 - %@",x);
}];
[connect.signal subscribeNext:^(id x) {
NSLog(@"3 - %@",x);
}];
#注意,最后一定要connect
[connect connect];
6.信号操作
1.串联concat
按一定顺序拼接信号,当多个信号发出的时候,有顺序的接收信号
#创建一个信号管A
RACSignal *siganlA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"吃饭"];
[subscriber sendCompleted];
return nil;
}];
#创建一个信号管B
RACSignal *siganlB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"吃的饱饱的,才可以睡觉的"];
[subscriber sendCompleted];
return nil;
}];
#串联管A和管B
RACSignal *concatSiganl = [siganlA concat:siganlB];
#不需要单独订阅signalA,signalB
#串联后的接收端处理 ,两个事件,走两次,
#第一个打印siggnalA的结果,
#第二次打印siganlB的结果
#第一个信号必须发送完成,第二个信号才会被激活
[concatSiganl subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
2021-08-19 10:48:44.780369+0800 RAC[22305:2852537] 吃饭
2021-08-19 10:48:44.780533+0800 RAC[22305:2852537] 吃的饱饱的,才可以睡觉的
2. 并联merge
按顺序合并多个信号为一个信号,其中前一个信号不添加sendCompleted,也会执行后面一个信号。只要有一个信号来,合并操作就会接受。
#创建信号A
RACSignal *siganlA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"纸厂污水"];
[subscriber sendCompleted];
return nil;
}];
#创建信号B
RACSignal *siganlB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"电镀厂污水"];
[subscriber sendCompleted];
return nil;
}];
#并联两个信号,根上面一样,分两次打印
RACSignal *mergeSiganl = [RACSignal merge:@[siganlA,siganlB]];
[mergeSiganl subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
2021-08-19 14:14:01.471138+0800 RAC[26049:2966473] 纸厂污水
2021-08-19 14:14:01.471334+0800 RAC[26049:2966473] 电镀厂污水
3.combineLatest
将多个信号合并起来,并且拿到各个信号的最新的值,必须每个合并的signal至少都有过一次sendNext,才会触发合并的信号。(跟zipWith相似)
reduce: 把信号发出元组的值聚合成一个值
#定义2个自定义信号
RACSubject *letters = [RACSubject subject];
RACSubject *numbers = [RACSubject subject];
#组合信号
[[RACSignal combineLatest:@[letters,numbers]
reduce:^(NSString *letter, NSString *number){
return [letter stringByAppendingString:number];
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
//自己控制发生信号值
[letters sendNext:@"A"];
[letters sendNext:@"B"];
[numbers sendNext:@"1"]; //打印B1
[letters sendNext:@"C"]; //打印C1
[numbers sendNext:@"2"];//打印C2
4. zipWith
把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元组,才会触发压缩流的next事件。
#创建信号A
RACSignal *siganlA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"红"];
[subscriber sendCompleted];
return nil;
}];
#创建信号B
RACSignal *siganlB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"白"];
[subscriber sendCompleted];
return nil;
}];
//合流后处理的是压缩包,需要解压后才能取到里面的值
[[siganlA zipWith:siganlB] subscribeNext:^(id x) {
//解压缩
RACTupleUnpack(NSString *stringA, NSString *stringB) = x;
NSLog(@"%@ %@",stringA, stringB);
}];
5. Map
把源信号的值映射成一个新的值,可以是任意类型的,也可以是信号
[[_textField.rac_textSignal map:^id(id value) {
#当源信号发出,就会调用这个block,修改源信号的内容
#返回值:就是处理完源信号的内容。
return [NSString stringWithFormat:@"输出:%@",value];
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"唱歌"];
[subscriber sendCompleted];
return nil;
}];
#对信号进行改进,当信号里面流的是唱歌.就改进为'跳舞'
RAC(self, tF.text) = [signalA map:^id(NSString *value) {
if ([value isEqualToString:@"唱歌"]) {
return @"跳舞";
}
return @"";
}];
6.flattenMap
用于把源信号内容映射成新的内容
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"打蛋液");
[subscriber sendNext:@"蛋液"];
[subscriber sendCompleted];
return nil;
}];
//对信号进行秩序秩序的第一步
signal = [signal flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
//处理上一步的RACSiganl的信号value.这里的value=@"蛋液"
NSLog(@"把%@倒进锅里面煎",value);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"煎蛋"];
[subscriber sendCompleted];
return nil;
}];
}];
//对信号进行第二步处理
signal = [signal flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
NSLog(@"把%@装载盘里",value);
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"上菜"];
[subscriber sendCompleted];
return nil;
}];
}];
//最后打印 最后带有===上菜
[signal subscribeNext:^(id x) {
NSLog(@"====%@",x);
}];
7.Then
忽略掉前一个信号发送的值,必须等前一个信号发送sendCompleted表示执行完成后,才执行下一个信号,否则无效,按信号忽略
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@1];
[subscriber sendCompleted];
return nil;
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@2];
return nil;
}];
}] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
#只能接收到第二个信号的值,也就是then返回信号的值
8. Filter
对订阅的信号进行筛选
#当UITextField内输入的内容长度大于5时,才会回调subscribeNext
[[[self.textField rac_textSignal] filter:^BOOL(NSString * _Nullable value) {
return value.length > 5;
}] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"filter result = %@", x);
}];
9. Ignore
对订阅的信号进行过滤
[[[self.textField rac_textSignal] ignore:@"666"] subscribeNext:^(NSString * _Nullable x) {
#当输入的内容 equalTo @"666" 时,这里不执行
#其他内容,均会执行subscribeNext
NSLog(@"ignore = %@", x);
}];
10. distinctUntilChanged
当上一次和当前的值不一样,就会发出内容
#在开发中,刷新UI经常使用,只有两次数据不一样才需要刷新
[[_textField.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
11. take
从开始一共取N次的信号
// 1、创建信号
RACSubject *signal = [RACSubject subject];
// 2、处理信号,订阅信号
[[signal take:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.发送信号
[signal sendNext:@1];
[signal sendNext:@2];
12. takeLast
取最后N次的信号,前提条件,订阅者必须调用完成,因为只有完成,就知道总共有多少信号.
// 1、创建信号
RACSubject *signal = [RACSubject subject];
// 2、处理信号,订阅信号
[[signal takeLast:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.发送信号
[signal sendNext:@1];
[signal sendNext:@2];
[signal sendCompleted];
13.takeUntil
获取信号直到某个信号执行完成
RACSignal *takeSiganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//创建一个定时器信号,每一秒触发一次
RACSignal *siganl = [RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]];
[siganl subscribeNext:^(id x) {
//在这里定时发送next玻璃球
[subscriber sendNext:@"直到世界尽头"];
}];
return nil;
}];
//创建条件信号
RACSignal *conditionSiganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//设置5s后发生complete
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"世界的今天到了,请下车");
[subscriber sendCompleted];
});
return nil;
}];
#设置条件,takeSiganl信号在conditionSignal信号接收完成前,不断取值
[[takeSiganl takeUntil:conditionSiganl] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
14. skip
skip:(NSUInteger):跳过几个信号,不接受。
// 表示输入第一次,不会被监听到,跳过第一次发出的信号
[[_textField.rac_textSignal skip:1] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
15. 延迟
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"等等我,我还有10s就到了");
[subscriber sendNext:@"北极"];
[subscriber sendCompleted];
return nil;
}];
//延迟10s接受next
[[siganl delay:10] subscribeNext:^(id x) {
NSLog(@"我到了%@",x);
}];
// 延时执行
[[RACScheduler mainThreadScheduler] afterDelay:2 schedule:^{
NSLog(@"2秒后执行我");
}];
16. 重放
当一个信号被多次订阅,反复播放内容
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"电影");
[subscriber sendNext:@"电影"];
[subscriber sendCompleted];
return nil;
}];
//创建该普通信号的重复信号
RACSignal *replaySiganl = [siganl replay];
//重复接受信号
[replaySiganl subscribeNext:^(NSString *x) {
NSLog(@"小米%@",x);
}];
[replaySiganl subscribeNext:^(NSString *x) {
NSLog(@"小红%@",x);
}];
17.定时
#创建定时器信号.定时8小时 重复发送信号
RACSignal *siganl = [RACSignal interval:60 * 60 * 8 onScheduler:[RACScheduler mainThreadScheduler]];
#定时器执行代码
[siganl subscribeNext:^(id x) {
NSLog(@"吃药");
}];
18.超时
超时,可以让一个信号在一定的时间后,自动报错。
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"我快到了");
RACSignal *sendSiganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:nil];
[subscriber sendCompleted];
return nil;
}];
//发生信号要1个小时10分钟才到
[[sendSiganl delay:60 * 70] subscribeNext:^(id x) {
//这里才发送next到siganl
[subscriber sendNext:@"我到了"];
[subscriber sendCompleted];
}];
return nil;
}];
[[siganl timeout:60 * 60 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) {
NSLog(@"%@",x);
} error:^(NSError * _Nullable error) {
NSLog(@"等了你一个小时,你一直没来,我走了");
}];
19. 重试
只要失败,就会重新执行创建信号中的block,直到成功
__block int failedCount = 0;
//创建信号
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
if (failedCount < 100) {
failedCount ++;
NSLog(@"我失败了");
[subscriber sendError:nil];
}else{
NSLog(@"经历了数百次后,我成功了");
[subscriber sendNext:nil];
}
return nil;
}];
//重试
RACSignal *retrySiganl = [siganl retry];
//直到发生next的玻璃球
[retrySiganl subscribeNext:^(id x) {
NSLog(@"重要成功了");
}];
20. 节流
当某个信号发送比较频繁时,可以使用节流,在某一段时间不发送信号内容,过了一段时间获取信号的最新内容发出
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
//即使发送一个next的Block
[subscriber sendNext:@"A"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"B"];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"C"];
[subscriber sendNext:@"D"];
[subscriber sendNext:@"E"];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"F"];
});
return nil;
}];
//对信号进行节流,限制时间内一次只能通过一个Block
[[signal throttle:1] subscribeNext:^(id x) {
NSLog(@"%@通过了",x);
}];