RACSignal
/**
*
一.核心:1.核心:信号类2.信号类的作用:只要有数据改变就会把数据包装成信号传递出去3.只要有数据改变就会有信号发出4.数据发出,并不是信号类发出,信号类不能发送数据一.使用方法:1.创建信号2.订阅信号二.实现思路:1.当一个信号被订阅,创建订阅者,并把nextBlock保存到订阅者里面。2.创建的时候会返回 [RACDynamicSignal createSignal:didSubscribe];3.调用RACDynamicSignal的didSubscribe4.发送信号[subscriber sendNext:value];5.拿到订阅者的nextBlock调用*/// 1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 3.发送信号[subscriber sendNext:@"ws"];// 4.取消信号,如果信号想要被取消,就必须返回一个RACDisposable// 信号什么时候被取消:1.自动取消,当一个信号的订阅者被销毁的时候机会自动取消订阅,2.手动取消,//block什么时候调用:一旦一个信号被取消订阅就会调用//block作用:当信号被取消时用于清空一些资源return [RACDisposable disposableWithBlock:^{ NSLog(@"取消订阅");}];}];// 2. 订阅信号//subscribeNext// 把nextBlock保存到订阅者里面// 只要订阅信号就会返回一个取消订阅信号的类RACDisposable *disposable = [signal subscribeNext:^(id x) { // block的调用时刻:只要信号内部发出数据就会调用这个blockNSLog(@"======%@", x);}];// 取消订阅[disposable dispose];}RACSignal使用步骤
/**
*1.创建信号 *2.订阅信号(订阅信号后,才会被激活) *3.发送信号 /RACSignal底层实现 1、创建信号,首先把didSubscribe保存到信号中,还不会触发 2、当信号被订阅,也就是调用signal的subscribrNext:nextBlock, subscribeNext内部会创建订阅者subscriber,并把nextBlock保存到subscriber中,subscribNext内部会调用signal的didSubscribe 3、signal的didsubcribe中调用【subscriber sendNext:@"发送数据"】,sendNext底层其实就是执行subscriber的nextBlock。 *///1.创建信号
RACSignal *mysignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { //2.发送信号 [subscriber sendNext:@"发送数据"]; [subscriber sendCompleted];//如果不再发送数据,需要调用完成方法,内部会调用 [self.disposable dispose]; return [RACDisposable disposableWithBlock:^{ NSLog(@"信号被销毁"); }]; }]; //3.订阅信号,才会激活信号 [mysignal subscribeNext:^(id x) { NSLog(@"接受到数据:%@",x); }];RACSubject
/**
*我们完全可以用RACSubject代替代理/通知,确实方便许多步骤:// 1.创建信号RACSubject *subject = [RACSubject subject];// 2.订阅信号[subject subscribeNext:^(id x) { // block:当有数据发出的时候就会调用// block:处理数据NSLog(@"%@",x);}];// 3.发送信号[subject sendNext:value];**注意:~~**RACSubject和RACReplaySubject的区别RACSubject必须要先订阅信号之后才能发送信号, 而RACReplaySubject可以先发送信号后订阅.可按实际情况各取所需。*/RACSubject使用步骤
/**
1、创建信号 【RACSubject subject】,跟RACSignal不一样,创建信号时没有block。 2、订阅信号 -(RACDisposable *)subscribeNext:(void(^)(id x)nextBlock) 3、发送信号 sengNext:(id Value) RACSubject : 底层实现跟RACSignal不一样 1、调用subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值了。 2、调用sendNext发送信号,遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock */ //1、创建信号 RACSubject *subject = [RACSubject subject]; //2、订阅信号 [subject subscribeNext:^(id x) { //block调用时刻:当信号发出新值,就会调用 NSLog(@"第一个订阅者:%@",x); }]; [subject subscribeNext:^(id x) { NSLog(@"第二个订阅者:%@",x); }]; //3、发送信号 [subject sendNext:@1]; [subject sendNext:@2];可以当通知来使用
也可以当做代理使用(在一个View中定义为属性,外部订阅,内容调用)
RACRepalySubject
//RACRepalySubject使用步骤
/** 1、创建信号 [RACReplaySubject subject] ,跟RACSignal不一样,创建信号时没有block 2、可以先发送信号,再订阅信号,RACSubject不可以!!! *订阅信号 -(RACDisposable)subscribeNext:(void(^)(id x))nextBlock *发送信号 sendNext:(id)value RACReplaySubject:底层实现和RACSubject不一样 1、调用sendNext发送信号,把值保存起来,然后遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock 2、调用subscribeNext订阅信号,遍历所有保存的值,一个一个调用订阅者的nextBlock 如果想当一个信号被订阅,就重复播放之前所有值,需要先发送信号,再订阅信号 也就是先保存值,再订阅值 */ //1、创建信号 RACReplaySubject *replaySubject = [RACReplaySubject replaySubjectWithCapacity:3]; //2、发送信号 [replaySubject sendNext:@1]; [replaySubject sendNext:@2]; //3、订阅信号 [replaySubject subscribeNext:^(id x) { NSLog(@"第一个订阅者收到的数据%@",x); }]; [replaySubject subscribeNext:^(id x) { NSLog(@"第二个订阅者收到的数据%@",x); }];两种的输出为:
/**
// 先订阅,后发送信号 2016-08-29 16:18:23.154 RACDemo[5507:185680] 第一个订阅者收到的数据1 2016-08-29 16:18:23.154 RACDemo[5507:185680] 第二个订阅者收到的数据1 2016-08-29 16:18:23.154 RACDemo[5507:185680] 第一个订阅者收到的数据2 2016-08-29 16:18:23.155 RACDemo[5507:185680] 第二个订阅者收到的数据2 *//**
// 先发送信号,再订阅 2016-08-29 16:19:43.945 RACDemo[5641:186739] 第一个订阅者收到的数据1 2016-08-29 16:19:43.945 RACDemo[5641:186739] 第一个订阅者收到的数据2 2016-08-29 16:19:43.946 RACDemo[5641:186739] 第二个订阅者收到的数据1 2016-08-29 16:19:43.946 RACDemo[5641:186739] 第二个订阅者收到的数据2 */RACSequence
元祖
NSArray
// 遍历数组
NSArray *array = @[@1,@2,@3]; // 1、把数组转换成集合RACSequence,array.rac_seuqence // 2、把集合RACSequence转换RACSignal信号类,array.rac_sequence.signal // 3、订阅信号,激活信号,会自动把集合中的所有值,遍历出来 [array.rac_sequence.signal subscribeNext:^(id x) { NSLog(@"%@",x); }];NSDictionary
// 遍历字典,遍历出来的键值会包装成RACTuple(元祖对象)
NSDictionary *dic = @{@"name":@"wangtongke",@"age":@18}; [dic.rac_sequence.signal subscribeNext:^(id x) { // 遍历字典 X为RAC的元祖(RACTuple) // 解包元祖,会把元祖的值,按顺序给参数里边的变量赋值 RACTupleUnpack(NSString *key,NSString *value) = x; // 以上 相当于一下写法 // NSString *key1 = x[0]; // NSString *value1 = x[1]; NSLog(@"%@ %@\n",key,value); }];RACComand
/**
1、创建命令 initWithSignalblock:(RACSignal * (^)(id input))signalBlock 2、在signalBlock中,创建RACSignal,并且作为signalBlock的返回值 3、执行命令 -(RACSignal *)execute:(id)input // 注意事项 1、signalBlock必须要返回一个signal,不能返回nil, 2、如果不想要传递信号,直接创建空的信号返回[RACSignal empty]; 3、RACCommand,如果数据传递完毕,必须调用[subscriber sendCompleted],这时命令才会执行完毕,否则永远处于执行中. 4、RACComand需要被强引用,否则接手不到RACCommand中的信号,因此,RACCommand中的信号是延迟发送的。 // 设计思想 : 内部signalBlock为什么要返回一直信号,这个信号有什么用 1、在RAC开发中,通常会把网络请求封装到RACCommand,直接执行某个RACCommand就能发送请求。 2、当RACCommand内部请求到数据的时候,需要把请求的数据传递给外界,这时候就需要通过signalBlock返回的信号传递了 // 如何拿到RACCommand中返回信号发出的数据 1、RACCommand有个执行信号源executionSignal,这个signal of signal(信号的信号),意思是发出的数据是信号,不是普通的类型 2、订阅executionSignal就能拿到RACCommand中返回的信号,然后订阅signalblock返回的信号。 // 监听当前命令是否正在执行executing // 使用场景 按钮点击,网络请求 */ // ******* 1、创建命令 RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) { NSLog(@"执行命令"); NSLog(@"input---%@",input); //必须返回信号 不能返回nil 创建空信号, //return [RACSignal empty]; // ******* 2、创建信号,用来传递数据 return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"请求数据"]; [subscriber sendNext:@"请求数据1"]; //注意:数据传递完,必须调用sendCompleted,这时命令才执行完毕 [subscriber sendCompleted]; return [RACDisposable disposableWithBlock:^{ }]; }]; }]; //强引用命令,不然会自动销毁,接受不到数据 _command = command; // ******* 3、订阅RACCommand中的信号 [command.executionSignals subscribeNext:^(id x) { [x subscribeNext:^(id x) { NSLog(@"%@",x); }]; }]; //高级用法 //switchToLatest:用于signal of signals,获取signal of signals 发出的最新的信号,也就是可以直接拿到RACCommand中的信号 [command.executionSignals.switchToLatest subscribeNext:^(id x) { NSLog(@"高级--%@",x); }]; // ******** 4、监听命令是否执行完毕,默认会来一次,可以直接跳过,skip表示跳过第一次信号 [[command.executing skip:0] subscribeNext:^(id x) { if ([x boolValue] == YES) { //正在执行 NSLog(@"正在执行"); } else { //执行完成 NSLog(@"执行完成"); } }]; // ******** 5、执行命令 [self.command execute:@1];RACMulticastConnection
解决多次订阅多次请求的问题,只有连接之后才调用所有订阅者的subscribeNext
/**
RACMulticastConnection使用步骤 **** 1、创建信号 +(RACSignal)createSignal **** 2、创建连接 RACMulticastConnection *connect = [signal publish]; **** 3、订阅信号,注意:订阅的不再是之前的信号,而是连接的信号[connect.signal subscribeNext]; **** 4、连接 [connect connect]; RACMulticastConnection底层原理 // 1.创建connect,connect.sourceSignal -> RACSignal(原始信号) connect.signal -> RACSubject // 2.订阅connect.signal,会调用RACSubject的subscribeNext,创建订阅者,而且把订阅者保存起来,不会执行block。 // 3.[connect connect]内部会订阅RACSignal(原始信号),并且订阅者是RACSubject // 3.1.订阅原始信号,就会调用原始信号中的didSubscribe // 3.2 didSubscribe,拿到订阅者调用sendNext,其实是调用RACSubject的sendNext // 4.RACSubject的sendNext,会遍历RACSubject所有订阅者发送信号。 // 4.1 因为刚刚第二步,都是在订阅RACSubject,因此会拿到第二步所有的订阅者,调用他们的nextBlock 需求 : 假设在一个信号中发送请求,每次订阅一次都会发送请求,这样就会导致多次请求。 解决 使用RACMulticastConnection。 */ // ********** 1、创建请求信号 RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@"发送请求111111"); [subscriber sendNext:@1]; return nil; }]; // ********** 2、订阅信号 [signal subscribeNext:^(id x) { NSLog(@"接受数据11111--%@",x); }]; // 订阅两次信号 [signal subscribeNext:^(id x) { NSLog(@"接受数据11111---%@",x); }]; //会执行两次发送请求。也就是每订阅一次 就会发送一次请求 //RACMulicastConnection解决重复请求问题 // ********** 1、创建信号 RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSLog(@"发送请求2"); [subscriber sendNext:@1]; return nil; }]; // ********** 2、 创建连接 RACMulticastConnection *connect = [signal2 publish]; // ********** 3、订阅信号 // 注意:订阅信号也不能激活信号,只是保存订阅者到数据,必须通过连接,当调用连接,就会一次清调用所有订阅者的sendNext; [connect.signal subscribeNext:^(id x) { NSLog(@"订阅者一信号"); }]; [connect.signal subscribeNext:^(id x) { NSLog(@"订阅者二信号"); }]; // ********** 4、连接 [connect connect];bind
/**
假设想监听文本框的内容,并且在每次输出结果的时候,都在文本框的内容拼接一段文字“输出:”
*/// bind(绑定)的使用思想和Hook的一样---> 都是拦截API从而可以对数据进行操作,,而影响返回数据。
// 发送信号的时候会来到30行的block。在这个block里我们可以对数据进行一些操作,那么35行打印的value和订阅绑定信号后的value就会变了。变成什么样随你喜欢喽。 // ******************方式1、 在返回结果后拼接// [_textField.rac_textSignal subscribeNext:^(id x) { // NSLog(@"输出:%@",x);// }];// ******************方式2、在返回结果前拼接,使用RAC中的bind方法做处理/** bind方法参数:需要传入一个返回值是RACSignalBindBlock的block参数 RACStreamBindBlock是一个block类型,返回值是信号,参数(Value,stop),因此参数的block返回值也是一个block RACStreamBindBlock: 参数一(value):表示接受到信号的原始值,还没有做处理 参数二(*stop): 用来控制绑定block,如果*stop = YES,那么就结束绑定 返回值:信号,做好处理,再通过这个信号返回出去,一般使用RACReturnSignal,需要手动导入头文件RACReturnSignal.h bind方法使用步骤 1、传入一个返回值RACStreamBindBlock的block 2、描述一个RACStreamBindBlock类型的bindBlock作为block的返回值 3、描述 */ [[_textField.rac_textSignal bind:^RACStreamBindBlock{ return ^RACStream *(id value,BOOL *stop){ return [RACReturnSignal return:[NSString stringWithFormat:@"输出:%@",value]]; }; }] subscribeNext:^(id x) { NSLog(@"%@",x); }];// 1.创建信号
RACSubject *subject = [RACSubject subject]; // 2.绑定信号 RACSignal *bindSignal = [subject bind:^RACStreamBindBlock{ // block调用时刻:只要绑定信号订阅就会调用。不做什么事情, return ^RACSignal *(id value, BOOL *stop){ // 一般在这个block中做事 ,发数据的时候会来到这个block。 // 只要源信号(subject)发送数据,就会调用block // block作用:处理源信号内容 // value:源信号发送的内容, value = @3; // 如果在这里把value的值改了,那么订阅绑定信号的值即44行的x就变了 NSLog(@"接受到源信号的内容:%@", value); //返回信号,不能为nil,如果非要返回空---则empty或 alloc init。 return [RACReturnSignal return:value]; // 把返回的值包装成信号 }; }]; // 3.订阅绑定信号 [bindSignal subscribeNext:^(id x) { NSLog(@"接收到绑定信号处理完的信号:%@", x); }]; // 4.发送信号 [subject sendNext:@"123"];RACMethod
// ********************** 1、代替代理 **************************
/** 需求: 自定义redView,监听redView中按钮点击 之前都是需要通过代理监听,给红色view添加一个代理属性,点击按钮的时候,通知代理做事情 rac_signalForSelector:把调用某个对象的方法的信息转换成信号,只要调用这个方法,就会发送信号 这里表示只要redView调用btnClick,就会发出信号,只需要订阅就可以了 */ WTKView *view = [[WTKView alloc]initWithFrame:CGRectMake(0, 200, 375, 200)]; [self.view addSubview:view]; [[view rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) { NSLog(@"点击红色按钮---%@",x); //怎么传值???? }]; // ********************** 2、KVO ************************** [[view rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) { NSLog(@"%@",x); }]; view.center = CGPointMake(100, 100); // ********************** 3、监听事件 ************************** UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom]; btn.backgroundColor = [UIColor purpleColor]; btn.frame = CGRectMake(300, 300, 200, 30); [btn setTitle:@"RAC" forState:UIControlStateNormal]; [self.view addSubview:btn]; [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) { NSLog(@"按钮被点击了"); }]; // ********************** 4、代替通知 ************************** // 把监听到的通知,转换成信号 [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) { NSLog(@"键盘弹出"); }]; // ********************** 5、监听文本框文字改变 ************************** [self.textField.rac_textSignal subscribeNext:^(id x) { NSLog(@"文字改变了---%@",x); }]; // ********************** 6、处理多个请求,都返回结果的时候,统一做处理 ************************** RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendNext:@"发送请求1"]; return [RACDisposable disposableWithBlock:^{ }]; }]; RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [subscriber sendNext:@"发送请求2"]; }); return [RACDisposable disposableWithBlock:^{ }]; }]; // 使用注意:几个信号,参数一的方法就必须有几个参数,每个参数对应信号发出的数据 [self rac_liftSelector:@selector(wtkUpdateWithDic1:withDic2:) withSignalsFromArray:@[request1,request2]];skip
// 跳跃 : 如下,skip传入2 跳过前面两个值
//应用场景: 在实际开发中比如 后台返回的数据前面几个没用,我们想跳跃过去,便可以用skip- (void)skip { RACSubject *subject = [RACSubject subject]; [[subject skip:2] subscribeNext:^(id x) { NSLog(@"%@", x); }]; [subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3];}distinctUntilChanged
//应用场景:-- 如果当前的值跟上一次的值一样,就不会被订阅到
- (void)distinctUntilChanged { RACSubject *subject = [RACSubject subject]; [[subject distinctUntilChanged] subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送信号 [subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@2]; // 不会被订阅}take
// 应用场景:可以屏蔽一些值,去前面几个值---这里take为2 则只拿到前两个值
- (void)take { RACSubject *subject = [RACSubject subject]; [[subject take:2] subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送信号 [subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3];}takeLast
//应用场景:和take的用法一样,不过他取的是最后的几个值,如下,则取的是最后两个值
//注意点:takeLast 一定要调用sendCompleted,告诉他发送完成了,这样才能取到最后的几个值- (void)takeLast { RACSubject *subject = [RACSubject subject]; [[subject takeLast:2] subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送信号 [subject sendNext:@1]; [subject sendNext:@2]; [subject sendNext:@3]; [subject sendCompleted];}takeUntil
//应用场景:---给takeUntil传的是哪个信号,那么当这个信号发送信号或sendCompleted,就不能再接受源信号的内容了。
- (void)takeUntil { RACSubject *subject = [RACSubject subject]; RACSubject *subject2 = [RACSubject subject]; [[subject takeUntil:subject2] subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送信号 [subject sendNext:@1]; [subject sendNext:@2]; [subject2 sendNext:@3]; // 1// [subject2 sendCompleted]; // 或2 [subject sendNext:@4];}ignore
//应用场景: 忽略掉一些值
- (void)ignore { //ignore:忽略一些值 //ignoreValues:表示忽略所有的值 // 1.创建信号 RACSubject *subject = [RACSubject subject]; // 2.忽略一些值 RACSignal *ignoreSignal = [subject ignore:@2]; // ignoreValues:表示忽略所有的值 // 3.订阅信号 [ignoreSignal subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 4.发送数据 [subject sendNext:@2];}fliter
// 一般和文本框一起用,添加过滤条件
- (void)fliter { // 只有当文本框的内容长度大于5,才获取文本框里的内容 [[self.textField.rac_textSignal filter:^BOOL(id value) { // value 源信号的内容 return [value length] > 5; // 返回值 就是过滤条件。只有满足这个条件才能获取到内容 }] subscribeNext:^(id x) { NSLog(@"%@", x); }];}map
- (void)map {
// 创建信号 RACSubject *subject = [RACSubject subject]; // 绑定信号 RACSignal *bindSignal = [subject map:^id(id value) { // 返回的类型就是你需要映射的值 return [NSString stringWithFormat:@"ws:%@", value]; //这里将源信号发送的“123” 前面拼接了ws: }]; // 订阅绑定信号 [bindSignal subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送信号 [subject sendNext:@"123"];}flattenMap
应用场景: 主要用于信号中的信号
- (void)flattenMap {
// 创建信号 RACSubject *subject = [RACSubject subject]; // 绑定信号 RACSignal *bindSignal = [subject flattenMap:^RACStream *(id value) { // block:只要源信号发送内容就会调用 // value: 就是源信号发送的内容 // 返回信号用来包装成修改内容的值 return [RACReturnSignal return:value]; }]; // flattenMap中返回的是什么信号,订阅的就是什么信号(那么,x的值等于value的值,如果我们操纵value的值那么x也会随之而变) // 订阅信号 [bindSignal subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送数据 [subject sendNext:@"123"];}- (void)flattenMap2 {
// 创建信号
RACSubject *signalofSignals = [RACSubject subject]; RACSubject *signal = [RACSubject subject]; // 订阅信号 //方式1 // [signalofSignals subscribeNext:^(id x) { // // [x subscribeNext:^(id x) { // NSLog(@"%@", x); // }]; // }]; // 方式2 // [signalofSignals.switchToLatest ]; // 方式3 // RACSignal *bignSignal = [signalofSignals flattenMap:^RACStream *(id value) { // // //value:就是源信号发送内容 // return value; // }]; // [bignSignal subscribeNext:^(id x) { // NSLog(@"%@", x); // }]; // 方式4--------也是开发中常用的 [[signalofSignals flattenMap:^RACStream *(id value) { return value; }] subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送信号 [signalofSignals sendNext:signal]; [signal sendNext:@"123"];}RAC常见宏
// RAC(TARGET, [KEYPATH, [NIL_VALUE]]):用于给某个对象的某个属性绑定。
RAC(self.label,text) = _textField.rac_textSignal; // RACObserve(self, name):监听某个对象的某个属性,返回的是信号 [RACObserve(self.label, text) subscribeNext:^(id x) { NSLog(@"%@",x); }]; // @weakify(Obj)和@strongify(Obj),一般两个都是配套使用,在主头文件(ReactiveCocoa.h)中并没有导入,需要自己手动导入,RACEXTScope.h才可以使用。但是每次导入都非常麻烦,只需要在主头文件自己导入就好了。 // 最新版库名 已换成 EXTScope // 两个配套使用,先weak再strong @weakify(self); // @strongify(self); [RACObserve(self, label.text) subscribeNext:^(id x) { @strongify(self); }]; // RACTuplePack:把数据包装成RACTuple(元组类) // 把参数中的数据包装成元祖 RACTuple *tuple = RACTuplePack(@10,@20); // RACTupleUnpack:把RACTuple(元组类)解包成对应的数据。 // 把参数再用的数据包装成元祖组合
combineLatest
//使用场景: 把多个信号聚合成你想要的信号,使用场景----:比如-当多个输入框都有值的时候按钮才可点击。
// 思路--- 就是把输入框输入值的信号都聚合成按钮是否能点击的信号。- (void)combineLatest { RACSignal *combinSignal = [RACSignal combineLatest:@[self.accountField.rac_textSignal, self.pwdField.rac_textSignal] reduce:^id(NSString *account, NSString *pwd){ //reduce里的参数一定要和combineLatest数组里的一一对应。 // block: 只要源信号发送内容,就会调用,组合成一个新值。 NSLog(@"%@ %@", account, pwd); return @(account.length && pwd.length); }]; // // 订阅信号 // [combinSignal subscribeNext:^(id x) { // self.loginBtn.enabled = [x boolValue]; // }]; // ----这样写有些麻烦,可以直接用RAC宏 RAC(self.loginBtn, enabled) = combinSignal;}zipWith
//使用场景:把两个信号压缩成一个信号,只有当两个信号同时发出信号内容时,并且把两个信号的内容合并成一个元祖,才会触发压缩流的next事件。
- (void)zipWith {
// 创建信号A RACSubject *signalA = [RACSubject subject]; // 创建信号B RACSubject *signalB = [RACSubject subject]; // 压缩成一个信号 // **-zipWith-**: 当一个界面多个请求的时候,要等所有请求完成才更新UI // 等所有信号都发送内容的时候才会调用 RACSignal *zipSignal = [signalA zipWith:signalB]; [zipSignal subscribeNext:^(id x) { NSLog(@"%@", x); //所有的值都被包装成了元组 }]; // 发送信号 交互顺序,元组内元素的顺序不会变,跟发送的顺序无关,而是跟压缩的顺序有关[signalA zipWith:signalB]---先是A后是B [signalA sendNext:@1]; [signalB sendNext:@2];}merge
// 任何一个信号请求完成都会被订阅到
//使用场景:多个信号合并成一个信号,任何一个信号有新值就会调用- (void)merge { // 创建信号A RACSubject *signalA = [RACSubject subject]; // 创建信号B RACSubject *signalB = [RACSubject subject]; //组合信号 RACSignal *mergeSignal = [signalA merge:signalB]; // 订阅信号 [mergeSignal subscribeNext:^(id x) { NSLog(@"%@", x); }]; // 发送信号---交换位置则数据结果顺序也会交换 [signalB sendNext:@"下部分"]; [signalA sendNext:@"上部分"];}then
//使用场景:有两部分数据:想让上部分先进行网络请求但是过滤掉数据,然后进行下部分的,拿到下部分数据
- (void)then { // 创建信号A RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 NSLog(@"----发送上部分请求---afn"); [subscriber sendNext:@"上部分数据"]; [subscriber sendCompleted]; // 必须要调用sendCompleted方法! return nil; }]; // 创建信号B, RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 NSLog(@"--发送下部分请求--afn"); [subscriber sendNext:@"下部分数据"]; return nil; }]; // 创建组合信号 // then;忽略掉第一个信号的所有值 RACSignal *thenSignal = [signalA then:^RACSignal *{ // 返回的信号就是要组合的信号 return signalsB; }]; // 订阅信号 [thenSignal subscribeNext:^(id x) { NSLog(@"%@", x); }];}concat
//使用场景:有两部分数据:想让上部分先执行,完了之后再让下部分执行(都可获取值)
- (void)concat { // 组合 // 创建信号A RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 // NSLog(@"----发送上部分请求---afn"); [subscriber sendNext:@"上部分数据"]; [subscriber sendCompleted]; // 必须要调用sendCompleted方法! return nil; }]; // 创建信号B, RACSignal *signalsB = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { // 发送请求 // NSLog(@"--发送下部分请求--afn"); [subscriber sendNext:@"下部分数据"]; return nil; }]; // concat:按顺序去链接 //**-注意-**:concat,第一个信号必须要调用sendCompleted // 创建组合信号 RACSignal *concatSignal = [signalA concat:signalsB]; // 订阅组合信号 [concatSignal subscribeNext:^(id x) { NSLog(@"%@",x); }];}网路请求应用场景
RACCommand *reuqesCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
RACSignal *requestSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; parameters[@"test"] = @""; // 发送请求 [[AFHTTPRequestOperationManager manager] GET:@"https://api.douban.com/v2/book/search" parameters:parameters success:^(AFHTTPRequestOperation * _Nonnull operation, id _Nonnull responseObject) { NSLog(@"%@",responseObject); // 请求成功调用 // 把数据用信号传递出去 [subscriber sendNext:responseObject]; [subscriber sendCompleted]; } failure:^(AFHTTPRequestOperation * _Nonnull operation, NSError * _Nonnull error) { // 请求失败调用 }]; return nil; }]; // 在返回数据信号时,把数据中的字典映射成模型信号,传递出去 return [requestSignal map:^id(NSDictionary *value) { NSMutableArray *dictArr = value[@"Persions"]; // 字典转模型,遍历字典中的所有元素,全部映射成模型,并且生成数组 NSArray *modelArr = [[dictArr.rac_sequence map:^id(id value) { return [Persion bookWithDict:value]; }] array]; return modelArr; }]; }];