美文网首页iOS开发
ReactiveObjC (二)

ReactiveObjC (二)

作者: wpf_register | 来源:发表于2020-06-07 23:44 被阅读0次

参考文档1
参考文档2
参考文档

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);
        
    }];
 

相关文章

网友评论

    本文标题:ReactiveObjC (二)

    本文链接:https://www.haomeiwen.com/subject/lbhktktx.html