Rac是个响应式框架,又称函数响应式编程。
RACSignal
//创建一个信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//发送信号
[subscriber sendNext:@"hello"];
return nil;
}];
//订阅信号
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
源码解读
可以当做block理解,订阅就是定义一个block,发送信号就是调用block
RACSubject
// RACSubject继承自RACSignal,但是对历史值不关心
//创建信号
RACSubject *subject = [[RACSubject alloc] init];
//订阅信号
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送信号
[subject sendNext:@"test1"];
[subject sendNext:@"test2"];
2021-07-01 09:24:06.934275+0800 ReactCoCoaDemo[83934:2200994] test1
2021-07-01 09:24:06.934353+0800 ReactCoCoaDemo[83934:2200994] test2
RACSubject 既可以发送信号也可以订阅信号
@implementation TGView
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self.subject sendNext:@"上班了"];
}
#pragma mark - lazy
- (RACSubject *)subject {
if (_subject == nil) {
_subject = [[RACSubject alloc] init];
}
return _subject;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupUI];
}
- (void)setupUI {
[self.actionView.subject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
}
@end
switchToLatest 最新信号
RACSubject * signalOfSignal = [RACSubject subject];
RACSubject * signal1 = [RACSubject subject];
RACSubject * signal2 = [RACSubject subject];
RACSubject * signal3 = [RACSubject subject];
//switchToLatest :最新的信号!!
[signalOfSignal.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送信号
[signalOfSignal sendNext:signal1];
[signalOfSignal sendNext:signal2];
[signalOfSignal sendNext:signal3];
//发送数据
[signal3 sendNext:@"3"];
[signal2 sendNext:@"2"];
[signal1 sendNext:@"1"];
//最后发送的信号是signal3 ,所以值是3
2021-07-01 15:21:43.184452+0800 ReactCoCoaDemo[88745:2454741] 3
RACDisposable
/*
当订阅者发送了sendCompleted 或senfError 就'相当于'结束订阅了, 可以理解成订阅者就销毁了
当订阅者没有被全局变量引用时, sendNext之后, 就'相当于'结束订阅了, 可以理解成订阅者就销毁了
当订阅者被销毁后,不会再发送信号
*/
//1、创建一个信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//3、发送信号
//subscriber 发送
[subscriber sendNext:@"发送信号"];
_subscriber = subscriber;//可以用self.,强引用一下subscriber就不会走下边了,不强引用着subscriber 的话subscriber在发送完之后就没了就 自动取消订阅了
//返回值的类型RACDisposable
//RACDisposable可以帮助我们取消订阅:信号发送完毕或者失败了。(就像通知的注册和注销)
return [RACDisposable disposableWithBlock:^{
//清空资源
NSLog(@"到这了");
}];
}];
//2、订阅信号
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) {
//x就是信号发送的内容
NSLog(@"订阅的信号是: %@",x);
}];
[disposable dispose];//手动 取消订阅
//信号发送完毕了 默认就会取消订阅
//只要订阅者在就不会主动取消订阅 如上边强引用着 subscriber 此时可以手动取消订阅
RAC_liftselecor
合并多个信号一次发送
- (void)setupData {
//请求1
RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//发送请求
NSLog(@"请求网络数据 1");
//发送数据
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"数据1 来了"];
});
return nil;
}];
//请求2
RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//发送请求
NSLog(@"请求网络数据 2");
//发送数据
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"数据2 来了"];
});
return nil;
}];
//数组:存放信号
//当数组中的所有洗好都发送了数据,才会执行Selector
//方法的参数:必须和数组的信号一一对应!!
//方法的参数:就是每一个信号发送的数据!!
[self rac_liftSelector:@selector(updateUIWithOneData:TwoData:) withSignalsFromArray:@[signal1,signal2]];
}
- (void)updateUIWithOneData:(id )oneData TwoData:(id )twoData {
NSLog(@"%@",[NSThread currentThread]);
//拿到数据更新UI
NSLog(@"UI!!%@%@",oneData,twoData);
}
RAC宏
RAC宏作用: 给对象属性绑定信号
//当textField内容发生变化时,就把内容赋值给label的text属性
RAC(_label,text) = _textField.rac_textSignal;
//输入框背景色绑定了映射后的validUserNameSignal信号,信号变化时背景色更新
RAC(self.userNameTxtField,backgroundColor) = [validUserNameSignal map:^id _Nullable(NSNumber *userNameValid) {
return [userNameValid boolValue] ? [UIColor whiteColor] : [UIColor yellowColor];
}];
RACObserve作用: 监听某个对象的属性
//当self.label里面的内容发生变化时,就会发送信号
[RACObserve(self.label, text) subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
RACTuplePack与RACTupleUnpack
- RACTuplePack:将数据封装成元组
- RACTupleUnpack:将元组解包为数据
//使用RACTuplePack封装元组
RACTuple *racTuple = RACTuplePack(@"字符串1",@"字符串2");
NSLog(@"测试racTuple:%@",racTuple);
//使用RACTupleUnpack解元组
RACTupleUnpack(NSString *str1,NSString *str2) = racTuple;
NSLog(@"测试RACTupleUnpack:%@-%@",str1,str2);
2021-07-03 14:46:26.456075+0800 ReactCoCoaDemo[22051:2378052] 测试racTuple:<RACTwoTuple: 0x6000001982f0> (
"\U5b57\U7b26\U4e321",
"\U5b57\U7b26\U4e322"
)
2021-07-03 14:46:26.456240+0800 ReactCoCoaDemo[22051:2378052] 测试RACTupleUnpack:字符串1-字符串2
@weakify、@strongify
- RAC中使用@weakify、@strongify解决Block循环引用的问题。
- 在block内部使用@strongify(self)后就可以使用self操作属性了,但是一定注意这两个宏定义一定要配合使用.可参考源码分析
@weakify(self);
//RAC处理手势,点击页面,隐藏键盘
[self.tapGesture.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
@strongify(self);
//经过宏定义处理后就可以使用self了,但此self非彼self。具体可查看源码分析
[self.view endEditing:YES];
}];
信号时间操作
interval
创建定时器信号,每固定时间发送一次信号
RACSignal *intervalSignal = [RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]];
//只知道使用take结束定时器这一种方法,不知道还有没有其他方法
[[intervalSignal take:5] subscribeNext:^(NSDate * _Nullable x) {
//订阅定时器信号,启动定时器,只打印5次
NSLog(@"%@",x);
}];
delay
延迟发送sendNext
RACSignal *delaySignal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"杭杭"];
return nil;
}];
//10秒后才收到消息,执行打印
[[delaySignal delay:10] subscribeNext:^(id _Nullable x) {
NSLog(@"延迟:%@",x);
}];
timeout
- 可以设置超时操作,让一个信号在规定时间之后自动报错
- 创建信号时不能使用sendCompleted,因为这样的话一旦发送了消息就取消订阅了。
RACSignal *timeOutSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"timeOutSignal发送信号"];
//[subscriber sendCompleted];
return nil;
}] timeout:5 onScheduler:[RACScheduler currentScheduler]];
[timeOutSignal subscribeNext:^(id _Nullable x) {
NSLog(@"timeOutSignal:%@",x);
} error:^(NSError * _Nullable error) {
//5秒后执行打印:
//timeOutSignal:出现Error-Error Domain=RACSignalErrorDomain Code=1 "(null)"
NSLog(@"timeOutSignal:出现Error-%@",error);
} completed:^{
NSLog(@"timeOutSignal:complete");
}];
信号发送顺序 doNext、doCompleted
- doNext:在订阅者发送消息sendNext之前执行
- doCompleted:在订阅者发送完成sendCompleted之后执行
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"发送信号:1"];
[subscriber sendCompleted];
return nil;
}];
[[[signal doNext:^(id _Nullable x) {
NSLog(@"执行doNext");
}] doCompleted:^{
NSLog(@"执行doComplete");
}] subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号:%@",x);
}];
2021-07-03 15:17:40.297460+0800 ReactCoCoaDemo[22624:2413314] 执行doNext
2021-07-03 15:17:40.297631+0800 ReactCoCoaDemo[22624:2413314] 订阅信号:发送信号:1
2021-07-03 15:17:40.297781+0800 ReactCoCoaDemo[22624:2413314] 执行doComplete
Retry
retry:只要失败就重新执行信号
static int signalANum = 0;
RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
if (signalANum == 3) {
[subscriber sendNext:@"signalANum is 5"];
[subscriber sendCompleted];
}else{
NSLog(@"signalANum错误!!!");
[subscriber sendError:nil];
}
signalANum++;
return nil;
}];
[[signalA retry] subscribeNext:^(id _Nullable x) {
NSLog(@"StringA-Next:%@",x);
} error:^(NSError * _Nullable error) {
//特别注意:这里并没有打印
NSLog(@"signalA-Errror");
}] ;
2021-07-03 15:48:21.917009+0800 ReactCoCoaDemo[23117:2434958] signalANum错误!!!
2021-07-03 15:48:21.965678+0800 ReactCoCoaDemo[23117:2434958] signalANum错误!!!
2021-07-03 15:48:21.965896+0800 ReactCoCoaDemo[23117:2434958] signalANum错误!!!
2021-07-03 15:48:21.966096+0800 ReactCoCoaDemo[23117:2434958] StringA-Next:signalANum is 3
RACMulticastConnection
当信号,被多次订阅时,为了避免多次调用创建信号中的block
//普通多次订阅型号,多次重复请求
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//发送信号
NSLog(@"发送热门模块请求");
[subscriber sendNext:@"1"];
return nil;
}];
//订阅信号
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"订阅1 : %@", x);
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"订阅2 : %@", x);
}];
2021-07-01 13:59:27.198749+0800 ReactCoCoaDemo[87616:2393341] 发送热门模块请求
2021-07-01 13:59:27.198889+0800 ReactCoCoaDemo[87616:2393341] 订阅1 : 1
2021-07-01 13:59:27.199095+0800 ReactCoCoaDemo[87616:2393341] 发送热门模块请求
2021-07-01 13:59:27.199166+0800 ReactCoCoaDemo[87616:2393341] 订阅2 : 1
// 1. 创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable* (id subscriber) {
NSLog(@"发送热门模块请求");
[subscriber sendNext:@1];
return nil;
}];
// 2. 把信号转换成连接类
RACMulticastConnection *signalConn = [signal publish];
// 确定源信号的订阅者RACSubject
// RACMulticastConnection *signalConn = [signal multicast:[RACReplaySubject subject]];
// 3. 多个订阅
[signalConn.signal subscribeNext:^(id _Nullable x) {
NSLog(@"订阅1 : %@", x);
}];
[signalConn.signal subscribeNext:^(id _Nullable x) {
NSLog(@"订阅2 : %@", x);
}];
[signalConn.signal subscribeNext:^(id _Nullable x) {
NSLog(@"订阅3 : %@", x);
}];
// 4. 连接
[signalConn connect];
2021-07-01 13:38:48.718610+0800 ReactCoCoaDemo[87290:2376442] 发送热门模块请求
2021-07-01 13:38:48.718764+0800 ReactCoCoaDemo[87290:2376442] 订阅1 : 1
2021-07-01 13:38:48.718851+0800 ReactCoCoaDemo[87290:2376442] 订阅2 : 1
2021-07-01 13:38:48.718930+0800 ReactCoCoaDemo[87290:2376442] 订阅3 : 1
RACCommond
RACCommond是用于处理事件的类,可以把事件如何处理,如何传递都封装到类中,之后就可以方便的调起它的执行方法。在实际开发中,我们可以用它来封装一个网络操作。
注意:
- 创建方法中block返回一个信号,且不能为nil,但是可以使用[RACSignal empty]表示空信号
- RACCommand必须被强引用,否则容易被释放
示例1
RACCommand *commond = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
NSLog(@"input:%@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"执行完命令之后产生的数据"];
return nil;
}];
}];
//执行命令
RACSignal *signal = [commond execute:@"输入的指令"];
//订阅信号
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
示例2
//1.创建RACCommand:initWithSignalBlock
self.command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
//我们常在这里创建一个网络请求的信号,也就是封装一个请求数据的操作。
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"网络请求的信号"];
//数据传递完成,必须调用sendComplleted.,否则永远处于执行中。
[subscriber sendCompleted];
return nil;
}];
return signal;
}];
//2.订阅RACCommand中的信号,要等到RACCommand执行后,才能收到消息
[self.command.executionSignals subscribeNext:^(id _Nullable x) {
//这里是一个信号中信号
[x subscribeNext:^(id _Nullable x) {
NSLog(@"收到信号:%@",x);
}];
}];
//改进订阅方法:switchToLatest可以直接获取信号中信号
[self.command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
NSLog(@"改进-收到信号:%@",x);
}];
//3.监听RACCommand命令是否执行完毕的信号
//默认会监测一次,所以可以使用skip表示跳过第一次信号。
//这里可以用于App网络请求时,控制加载提示视图的隐藏或者显示
[[self.command.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
if([x boolValue] == YES){
NSLog(@"RACCommand命令正在执行...");
}else{
NSLog(@"RACCommand命令不在执行中!!!");
}
}];
//4.执行RACComand
//方法:- (RACSignal *)execute:(id)input
[self.command execute:@"start"];
2021-07-03 14:37:18.213307+0800 ReactCoCoaDemo[21909:2369050] RACCommand命令正在执行...
2021-07-03 14:37:18.213722+0800 ReactCoCoaDemo[21909:2369050] 收到信号:网络请求的信号
2021-07-03 14:37:18.213857+0800 ReactCoCoaDemo[21909:2369050] 改进-收到信号:网络请求的信号
2021-07-03 14:37:18.214260+0800 ReactCoCoaDemo[21909:2369050] RACCommand命令不在执行中!!!
bind
//创建信号
RACSubject *subject = [[RACSubject alloc] init];
//绑定信号
RACSignal *bindSignal = [subject bind:^RACSignalBindBlock {
return ^ RACSignal *(id value,BOOL *stop){
return [RACReturnSignal return:value];
};
}];
//订阅信号
[bindSignal subscribeNext:^(id _Nullable x) {
NSLog(@"接收到: %@",x);
}];
//发送信号
[subject sendNext:@"原始数据"];
映射
flattenMap
//创建信号
RACSubject *subject = [[RACSubject alloc] init];
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:@"22"];
2021-07-01 16:15:29.503411+0800 ReactCoCoaDemo[89611:2497692] 处理数据:22
Map
//创建信号
RACSubject *subject = [[RACSubject alloc] init];
RACSignal *signal = [subject map:^id _Nullable(id _Nullable value) {
//返回信号用来包装修改过的内容
return [NSString stringWithFormat:@"处理数据:%@",value];
}];
//订阅信号
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送信号
[subject sendNext:@"123"];
[subject sendNext:@"321"];
distinctUntilChanged
当上一次的值和当前的值有变化就会发出信号,否则会被忽略掉。 在开发中,刷新UI经常使用,只有两次数据不一样才需要刷新
//创建信号
RACSubject*signal = [RACSubject subject];
//调用方法后订阅信号
[[signal distinctUntilChanged] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[signal sendNext:@"luobo"];
[signal sendNext:@"luobo"];
[signal sendNext:@"luobo"];
[signal sendNext:@"luo"];
2021-07-02 11:08:11.287061+0800 ReactCoCoaDemo[4515:3090401] luobo
2021-07-02 11:08:11.287226+0800 ReactCoCoaDemo[4515:3090401] luo
filter
过滤信号,获取满足条件的信号
//过滤信号,获取满足条件的信号
[[self.userTF.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
return value.length > 10;
}] subscribeNext:^(NSString * _Nullable x) {
self.pwdTF.backgroundColor = [UIColor blueColor];
}];
ignore
忽略完某些值的信号
//创建信号
RACSubject*signal = [RACSubject subject];
//ignore是忽略一些值
RACSignal*ignoreSignal = [signal ignore:@"luobo"];
//订阅信号
[ignoreSignal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送信号
[signal sendNext:@"luobo"];
[signal sendNext:@"crazy"];
2021-07-02 11:16:32.091836+0800 ReactCoCoaDemo[4645:3097841] crazy
信号取值
take、takeLast
//创建信号
RACSubject*subject = [RACSubject subject];
// take是取前面的几个值
//订阅信号
[[subject take:2] subscribeNext:^(id x) {
NSLog(@"###%@",x);
}];
// takeLast:去后面的多少个值,必须是发送完的
//只有调用[subject sendCompleted];才会发送信号
[[subject takeLast:2]subscribeNext:^(id x) {
NSLog(@"***%@",x);
}];
//发送数据
[subject sendNext:@"1"];
[subject sendNext:@"2"];
[subject sendNext:@"3"];
[subject sendCompleted];
[subject sendNext:@"4"];
2021-07-02 14:35:42.284337+0800 ReactCoCoaDemo[7431:3227190] ###1
2021-07-02 14:35:42.284516+0800 ReactCoCoaDemo[7431:3227190] ###2
2021-07-02 14:35:42.284667+0800 ReactCoCoaDemo[7431:3227190] ***2
2021-07-02 14:35:42.284724+0800 ReactCoCoaDemo[7431:3227190] ***3
takeUntil
RACSubject *signalA = [RACSubject subject];
[signalA subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号A:%@",x);
}];
__weak typeof(self)weakSelf = self;
//[RACObserve(self, currentText)发送消息直到signalA信号结束
[[RACObserve(self, currentText) takeUntil:signalA] subscribeNext:^(id _Nullable x) {
NSLog(@"打印结果:%@",x);
weakSelf.label.text = x;
}];
self.currentText = @"0";
self.currentText = @"1";
self.currentText = @"2";
[signalA sendNext:@"xxxx"];
[signalA sendCompleted];//信号A结束之后,监听testLabel文本的信号也不在发送消息了
self.currentText = @"3";
skip
RACSubject*subject = [RACSubject subject];
[[subject skip:2] subscribeNext:^(id x) {//跳跃过两个,执行下面的几个
NSLog(@"%@", x);
}];
[subject sendNext:@"hang"];
[subject sendNext:@"1"];
[subject sendNext:@"3"];
[subject sendNext:@"4"];
2021-07-02 14:59:38.208491+0800 ReactCoCoaDemo[7833:3247502] 3
2021-07-02 14:59:38.208576+0800 ReactCoCoaDemo[7833:3247502] 4
sequence
数组
NSArray *tempArray = @[@"rose",@"jerry",@"kati"];
[tempArray.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
字典
NSDictionary *dict = @{@"name":@"rose",@"age":@"18",@"height":@"1.67"};
[dict.rac_sequence.signal subscribeNext:^(id _Nullable x) {
// RACTupleUnpack(NSString *key,NSString *value) = x; 解元祖注意一一对应
RACTwoTuple *tuple = x;
NSLog(@"%@:%@ \n",tuple[0],tuple[1]);
}];
信号合并
combineLatest
RACSubject *signalOne = [RACSubject subject];
[signalOne subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号one:%@",x);
}];
RACSubject *signalTwo = [RACSubject subject];
[signalTwo subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号Two:%@",x);
}];
//多个信号都至少有过一次订阅信号sendNext的操作,才会触发合并的信号
[[RACSignal combineLatest:@[signalOne,signalTwo]] subscribeNext:^(RACTuple * _Nullable x) {
//解元组:合并信号得到的是一个元组,里面存放的是两个信号发送的消息
RACTupleUnpack(NSString *str1,NSString *str2) = x;
NSLog(@"combineLatest:结果1:%@,结果2:%@",str1,str2);
}];
[signalOne sendNext:@"1"];
[signalTwo sendNext:@"2"];
reduce
信号聚合,combineLatest合并后的信号订阅,得到的是一个元组,然而在开发中,我们往往需要检测多个信号合并后的效果(比如用户名和密码信号有效时,登录按钮才可以点击),这里就用到了reduce来实现信号聚合
RACSubject *signalOne = [RACSubject subject];
[signalOne subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号one:%@",x);
}];
RACSubject *signalTwo = [RACSubject subject];
[signalTwo subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号Two:%@",x);
}];
//多个信号都至少有过一次订阅信号sendNext的操作,才会触发合并的信号
[[RACSignal combineLatest:@[signalOne,signalTwo] reduce:^id(NSString *strOne,NSString *strTwo){
return [NSString stringWithFormat:@"%@-%@",strOne,strTwo];
}] subscribeNext:^(RACTuple * _Nullable x) {
NSLog(@"combineLatest-reduce:%@",x);
}];
[signalOne sendNext:@"1"];
[signalTwo sendNext:@"2"];
2021-07-02 16:27:20.003904+0800 ReactCoCoaDemo[9024:3313688] 订阅信号one:1
2021-07-02 16:27:20.004070+0800 ReactCoCoaDemo[9024:3313688] 订阅信号Two:2
2021-07-02 16:27:20.004285+0800 ReactCoCoaDemo[9024:3313688] combineLatest-reduce:1-2
merge
RACSubject *signalOne = [RACSubject subject];
[signalOne subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号one:%@",x);
}];
RACSubject *signalTwo = [RACSubject subject];
[signalTwo subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号Two:%@",x);
}];
RACSignal *mergeSignal = [signalOne merge:signalTwo];
[mergeSignal subscribeNext:^(id _Nullable x) {
NSLog(@"合并信号:%@",x);
}];
//只调用其中一个信号,就会触发merge合并的信号
[signalOne sendNext:@"1"];
[signalTwo sendNext:@"2"];
2021-07-02 16:46:30.205544+0800 ReactCoCoaDemo[9315:3329504] 订阅信号one:1
2021-07-02 16:46:30.205685+0800 ReactCoCoaDemo[9315:3329504] 合并信号:1
2021-07-02 16:46:30.205865+0800 ReactCoCoaDemo[9315:3329504] 订阅信号Two:2
2021-07-02 16:46:30.205928+0800 ReactCoCoaDemo[9315:3329504] 合并信号:2
zipWith
- zipWith把两个信号压缩成为一个信号,只有当两个信号同时发出信号时,两个信号的内容才会被合并为一个元组,触发压缩流的next事件。
- 比如:当一个界面多个请求的时候,要等所有请求完成才更新UI。
- 元组内元素顺序只与压缩信号的顺序有关,与发送信号的顺序无关
RACSubject *signalOne = [RACSubject subject];
[signalOne subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号one:%@",x);
}];
RACSubject *signalTwo = [RACSubject subject];
[signalTwo subscribeNext:^(id _Nullable x) {
NSLog(@"订阅信号Two:%@",x);
}];
RACSignal *zipSignal = [signalOne zipWith:signalTwo];
[zipSignal subscribeNext:^(id _Nullable x) {
//解元组:合并信号得到的是一个元组,里面存放的是两个信号发送的消息
RACTupleUnpack(NSString *str1,NSString *str2) = x;
NSLog(@"zipSignal:%@,%@",str1,str2);
}];
[signalOne sendNext:@"zipSignalOne"];
[signalTwo sendNext:@"zipSignalTwo"];
2021-07-02 16:55:43.208307+0800 ReactCoCoaDemo[9519:3338914] 订阅信号one:zipSignalOne
2021-07-02 16:55:43.208468+0800 ReactCoCoaDemo[9519:3338914] 订阅信号Two:zipSignalTwo
2021-07-02 16:55:43.208601+0800 ReactCoCoaDemo[9519:3338914] zipSignal:zipSignalOne,zipSignalTwo
综合案例
场景:比如用户名和密码信号有效时,登录按钮才可以点击
RACSignal *userSignal = [self.userTF.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
if (value.length >=5 && value.length <= 10) {
return @(YES);
}
return @(NO);
}];
//combineLatest 信号合并,拿到各个信号的最新的值,每个合并的signal至少都有过一次sendNext,才会触发合并的信号
//reduce 把信号发出元组的值聚合成一个值
RACSignal *pwdSignal = [self.pwdTF.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
if (value.length >=5 && value.length <= 10) {
return @(YES);
}
return @(NO);
}];
//信号绑定宏
RAC(self.loginBtn,userInteractionEnabled) = [RACSignal combineLatest:@[userSignal,pwdSignal] reduce:^id(NSNumber *userRes,NSNumber *pwdRes){
return @(userRes.boolValue && pwdRes.boolValue);
}];
信号拼接
contact
- 使用concat可以按序拼接多个信号,拼接后的信号按序执行。
- 使用concat连接信号后,每个信号无需再单独订阅,其内部会按序自动订阅
- 前面的信号必须执行sendCompleted,后面的信号才会被激活
RACSignal *signalOne = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"signalOne"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalTwo = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"signalTwo"];
[subscriber sendCompleted];
return nil;
}];
RACSignal *signalThree = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"signalThree"];
[subscriber sendCompleted];
return nil;
}];
//拼接了三个信号,订阅之后,三个信号依次激活
RACSignal *concatSignal = [[signalOne concat:signalThree] concat:signalTwo];
[concatSignal subscribeNext:^(id _Nullable x) {
NSLog(@"信号被激活:%@",x);
}];
2021-07-02 17:08:13.103446+0800 ReactCoCoaDemo[9687:3348607] 信号被激活:signalOne
2021-07-02 17:08:13.103610+0800 ReactCoCoaDemo[9687:3348607] 信号被激活:signalThree
2021-07-02 17:08:13.103720+0800 ReactCoCoaDemo[9687:3348607] 信号被激活:signalTwo
then
- 使用then连接信号,上一个信号完成后,才会连接then返回的信号,所以then连接的上一个信号必须使用sendCompleted,否则后续信号无法执行。
- then连接的多个信号与concat不同的是:之前的信号会被忽略掉,即订阅信号只会接收到最后一个信号的值
[[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"信号1");
[subscriber sendNext:@"发送信号1"];
[subscriber sendCompleted];
return nil;
}] then:^RACSignal *{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"信号2");
[subscriber sendNext:@"发送信号2"];
[subscriber sendCompleted];
return nil;
}];
}]then:^RACSignal * _Nonnull{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"信号3");
[subscriber sendNext:@"发送信号3"];
[subscriber sendCompleted];
return nil;
}];
}] subscribeNext:^(id x) {
//只能接收到最后一个信号的值
NSLog(@"订阅信号:%@",x);
}];
2021-07-02 17:18:02.363115+0800 ReactCoCoaDemo[9823:3356132] 信号1
2021-07-02 17:18:02.363388+0800 ReactCoCoaDemo[9823:3356132] 信号2
2021-07-02 17:18:02.363585+0800 ReactCoCoaDemo[9823:3356132] 信号3
2021-07-02 17:18:02.363657+0800 ReactCoCoaDemo[9823:3356132] 订阅信号:发送信号3