ReactiveCocoa 个人学习笔记记录(二)

WechatIMG7.jpeg

之前就一直在看ReactiveCocoa 相关知识 但是有感觉每次看完收货甚微,且感觉零零散散 ,本blog 仅仅是记录自己的学习过程

文章目录

  • 1 ReactiveCocoa 核心方法Bind
  • 2 ReactiveCocoa 之映射(flattenMap,Map)
    • 2-1 flattenMap和Map的区别
  • 3 ReactiveCocoa 操作方法之组合
    • 3-1 concat 按顺序的接受信号
    • 3-2 then 用于连接两个信号 当第一个信号完成 才会连接then返回的信号
    • 3-3 merge 把多个信号合并成一个信号 任何一个信号有新值的时候就会调用
    • 3-4 zipWith 把两个信号压缩成一个信号 只有当两个信号同时发出信号内容时 并且把两个信号的内容合并成一个元祖 才会触发压缩流的next事件
    • 3-5 combineLatest 将多个信号合并起来 并且拿到各个信号的最新的值 必须每个合并的signal至少都有过一次sendNext 才会触发合并的信号 和zipwith 差不多
  • 3-6 reduce(减少,降低 ,归纳) 聚合 用于信号发出的内容是元祖 把信号发出元祖的值聚合成一个值 然后通过reduce返回出来
  • 4 ReactiveCocoa 操作方法之过滤
    • 4-1 filter: 过滤信号 使用他可以获取满足条件的信号
    • 4-2 ignore 忽略某些值 的信号
    • 4-3 distinctUntilChanged 当上一次的值和当前的值不一样才会发出信号 如果两次的值一样 就不会发出信号
    • 4-4 take 取出信号 取出前几个信号
    • 4-5 takeLast 取最后N次的信号 前提条件订阅者必须调用完成 因为只有完成才知道总共有多少个信号
    • 4-6 takeUntil(RACSignal *)获取信号直到某个信号执行完成
    • 4-7 skip:(NSUInteger):跳过几个信号 不接收
  • 5 ReactiveCocoa 操作方法之秩序
    • 5-1 doNext 执行next之前会先执行这个block
    • 5-2 doComplete 执行sendComplete就会调用这个方法
  • 6 ReactiveCocoa 操作方法之时间
    • timeout: 超时 可以让一个信号在一定的时间后 自动报错
    • interval: 定时 每隔一段时间就发出信号
    • delay 延迟发送next
  • 7 ReactiveCocoa 操作方法之重复
    • retry 重试 只要失败 就一直执行信号中的block 直到成功
    • replay 重放 当一个信号被多次订阅 反复播放内容(没什么卵用)

一 ReactiveCocoa常见操作方法介绍

1.1 ReactiveCocoa 核心方法Bind
  • ReactiveCocoa操作的核心方法是bind(绑定),而且RAC中核心开发方式,也是绑定,之前的开发方式是赋值,而用RAC开发,应该把重心放在绑定,也就是可以在创建一个对象的时候,就绑定好以后想要做的事情,而不是等赋值之后在去做事情。

  • 列如:把数据展示到控件上,之前都是重写控件的setModel方法,用RAC就可以在一开始创建控件的时候,就绑定好数据。

  • 在开发中很少使用bind方法,bind属于RAC中的底层方法,RAC已经封装了很多好用的其他方法,底层都是调用bind,用法比bind简单.

  • bind 方法简单的介绍和使用

// 拼接内容
// 方式一   拿到结果后拼接内容
    [self.textFiled.rac_textSignal subscribeNext:^(id x) {
        NSLog(@"内容:%@",x);
    }];


// 方式二  拿到结果之前 进行拼接 利用Bind方法处理
//  处理原有信号  对信号进行加工
    // bind 方法参数  需要传入一个返回值是 RACStreamBindBlock 的参数
    // RACStreamBindBlock 是一个block类型  返回值是信号  参数是value和stop  因此参数block返回值也是一个block
            
    // RACStreamBindBlock
    // value 表示接收到信号的原始值 还没做处理
    // *stop 用来控制绑定block 如果 *stop = yes 那么就会结束绑定
    // 返回值: 信号 做好处理 在通过这个信号返回出去 一般使用RACreturnsignal,需要手动导入头文件RACReturnSignal.h
        
    // bind方法使用步骤:
    // 1 传入一个返回值为 RACStreamBindBlock 的bindblock
    // 2 描述一个RACStreamBindBlock 类型的bindblock作为block的返回值
    // 3 描述一个返回结果的信号 作为bindblock的返回值
    //  在bindblock中做信号结果的处理
    
    // 底层实现:
    // 1 源信号调用bind,会重新创建一个绑定信号。
    // 2 当绑定信号被订阅,就会调用绑定信号中的didSubscribe,生成一个bindingBlock。
    // 3 当源信号有内容发出,就会把内容传递到bindingBlock处理,调用bindingBlock(value,stop)
    // 4 调用bindingBlock(value,stop),会返回一个内容处理完成的信号(RACReturnSignal)。
    // 5 订阅RACReturnSignal,就会拿到绑定信号的订阅者,把处理完成的信号内容发送出来。
    
    [[self.textFiled.rac_textSignal bind:^RACStreamBindBlock{
                    
        return ^RACStream *(id value,BOOL *stop){
                    
            return [RACReturnSignal return:[NSString stringWithFormat:@"输出%@",value]];
            
        };
    }] subscribeNext:^(id x) {
      
        NSLog(@"%@",x);
        
    }];

1.2 映射(flattenMap,Map)
  • 这两者主要是把源信号 内容映射成新的内容
----  flattenMap : 把原信号的内容映射成一个新信号 信号可以是任意的类型

    // flattenMap使用步骤:    
  // 1.传入一个block,block类型是返回值RACStream,参数value   
 // 2.参数value就是源信号的内容,拿到源信号的内容做处理 
 // 3.包装成RACReturnSignal信号,返回出去。

    [[self.textFiled.rac_textSignal flattenMap:^RACStream *(id value) {     
        
        // 原信号发出的时候就会调用block
        // block作用 : 改变原信号的内容
                
        //  返回值  绑定信号的内容
        return [RACReturnSignal return:[NSString stringWithFormat:@"内容%@",value]];
                     
    }]subscribeNext:^(id x) {              
        NSLog(@"%@",x);
        
    }];


---- map: 把原信号的值映射成一个新值 

//    map 的使用步骤
    // 1 传入一个block 类型是返回对象 参数是value
    // 2 value就是原信号的内容 直接拿到原信号的内容做处理
    // 3 吧处理好的内容直接返回就好了 不用包装成信号   返回的值就是映射的值



    [[self.textFiled.rac_textSignal map:^id(id value) {
        
        return [NSString stringWithFormat:@"内容:%@",value];
        
    }]subscribeNext:^(id x) {
      
        NSLog(@"%@",x);
    }];

  • FlatternMap 和 Map的区别

  • 1 FlatternMap 中的block返回的是信号

  • 2 Map中的block返回对象

  • 3 开发中,如果信号发出的值不是信号 映射一般使用Map

  • 4 开发中 如果信号发出的是信号 映射一般使用FlatternMap

  • signalOfSignals 信号的信号 用FlatternMap


    RACSubject *signalOfsignals = [RACSubject  subject];
    
    RACSubject *signal = [RACSubject subject];
    
    [[signalOfsignals flattenMap:^RACStream *(id value) {
     
        // 当signalOfsignal 的signal发发出信号才会调用
        NSLog(@"拦截%@",value);

        return value;        
    }] subscribeNext:^(id x) {        
        NSLog(@"内容%@",x);        
    }];
    
    // 信号的信号发送信号
    [signalOfsignals sendNext:signal];
    
    [signal sendNext:@"奥卡姆剃须刀"];
    
1.3 ReactiveCocoa 操作方法值组合
  • concat 按一定顺序拼接信号 当多个信号发出的时候有顺序的接受信号
//    按一定顺序拼接信号 当多个信号发出的时候有顺序的接受信号    
    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
            [subscriber sendNext:@"我是一号"];
            
            [subscriber sendCompleted];
        
        return nil;
    }];
        
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                
        [subscriber sendNext:@"我是二号"];
        
        [subscriber sendCompleted];
        
        return nil;
    }];
        
    RACSignal *concatSignal = [signal2 concat:signal1];
    
    //  只有第一个信号完成后 才会执行第二个信号
    [concatSignal subscribeNext:^(id x) {
        
        NSLog(@"%@",x);
        
    }];

  • then 用于连接两个信号 当第一个信号完成 才会连接then返回的信号
    RACSignal *oneSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {                
        [subscriber sendNext:@"我是信号"];        
        //  只有当第一个信号完成后 第二个信号才会执行
        [subscriber sendCompleted];        
        return nil;        
    }];    
    RACSignal *twoSignal = [oneSignal   then:^RACSignal *{        
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {            
            [subscriber sendNext:@"我是第二个的信号"];            
            [subscriber sendCompleted];            
            return nil;
        }];        
    }];    
    // 订阅第一个信号
    [oneSignal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];    
    // 订阅第二个信号  只有第一个信号完成后 第二个信号发挥被触发
    [twoSignal  subscribeNext:^(id x) {                
        NSLog(@"%@",x);
    }];

  • merge 把多个信号合并成一个信号 任何一个信号有新值的时候就会调用


    // 底层实现:
    // 1.合并信号被订阅的时候,就会遍历所有信号,并且发出这些信号。
    // 2.每发出一个信号,这个信号就会被订阅
    // 3.也就是合并信号一被订阅,就会订阅里面所有的信号。
    // 4.只要有一个信号被发出就会被监听。


RACSignal *oneSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        
        [subscriber sendNext:@"我是第一个信号"];
        
        [subscriber sendCompleted];
        
        return nil;
        
    }];
    
    RACSignal *twoSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            
            [subscriber sendNext:@"我是第二个的信号"];
            
            [subscriber sendCompleted];
            
            return nil;
    }];

    
    RACSignal *mergeSignal = [oneSignal merge:twoSignal];
    
    [mergeSignal subscribeNext:^(id x) {
       
        NSLog(@"%@",x);
        
    }];
    
  • zipWith 把两个信号压缩成一个信号 只有当两个信号同时发出信号内容时 并且把两个信号的内容合并成一个元祖 才会触发压缩流的next事件

    RACSignal *oneSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {                
        [subscriber sendNext:@"我是第一个信号"];        
        [subscriber sendCompleted];        
        return nil;        
    }];
    
    RACSignal *twoSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {        
        [subscriber sendNext:@"我是第二个的信号"];        
        [subscriber sendCompleted];        
        return nil;
    }];    

    RACSignal *zipSignal = [oneSignal zipWith:twoSignal];    

//  合并出来是元祖  要想拿到元祖 要对元祖进行解包
    [zipSignal subscribeNext:^(id x) {                       
        RACTupleUnpack(id data1,id  data2) = x;        
        NSLog(@"%@---%@",data1,data2);        
    }];
    
  • combineLatest 将多个信号合并起来 并且拿到各个信号的最新的值 必须每个合并的signal至少都有过一次sendNext 才会触发合并的信号 和zipwith 差不多
    RACSignal *oneSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        
        [subscriber sendNext:@"我是第一个信号"];
        
        [subscriber sendCompleted];
        
        return nil;
        
    }];
    
    RACSignal *twoSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        [subscriber sendNext:@"我是第二个的信号"];
        
        [subscriber sendCompleted];
        
        return nil;
    }];

    
    //  必须两个都发信号 才会触发合并信号  和zipWith 一样没什么区别  也是会组装成元祖
    RACSignal *combineSignal = [oneSignal combineLatestWith:twoSignal];
    
    [combineSignal subscribeNext:^(id x) {       
        RACTupleUnpack(id data1,id data2) = x;        
        NSLog(@"%@--%@",data1,data2);        
    }];
  • reduce(减少,降低 ,归纳) 聚合 用于信号发出的内容是元祖 把信号发出元祖的值聚合成一个值 然后通过reduce返回出来

    
    RACSignal *oneSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        
        [subscriber sendNext:@"我是第一个信号"];
        
        [subscriber sendCompleted];
        
        return nil;
        
    }];
    
    RACSignal *twoSignal =  [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        [subscriber sendNext:@"我是第二个的信号"];
        
        [subscriber sendCompleted];
        
        return nil;
    
    }];
    
    // 聚合
    // 常见的用法 (先组合在聚合)
    
    // combineLatee里边有多少个参数组合  后边的reduce就应该有多少个参数
    
    //  reduce 返回值是聚合之后的内容
    
    
    RACSignal *reduceSignal = [RACSignal combineLatest:@[oneSignal,twoSignal] reduce:^id(NSString *data1,NSString *data2){
        
        return [NSString stringWithFormat:@"我是数据一%@---我是数据二%@",data1,data2];
        
    }];
    
    [reduceSignal subscribeNext:^(id x) {
       
        NSLog(@"%@",x);
        
        
    }];

1.4 ReactiveCocoa 操作方法之过滤
  • filter: 过滤信号 使用他可以获取满足条件的信号
   RACSignal *newSignal =  [self.textFiled.rac_textSignal filter:^BOOL(NSString * value) {       
        return value.length > 3;        
    }];    
// 只有长度大于三的字符串才能被打印粗来
    [newSignal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
    
  • ignore 忽略某些值 的信号
    // 只能忽略相等的值  其他的都忽略不了 内部调用的是filter过滤
    [[self.textFiled.rac_textSignal ignore:@"123"] subscribeNext:^(id x) {       
        NSLog(@"%@",x);        
    }];
  • distinctUntilChanged 当上一次的值和当前的值不一样才会发出信号 如果两次的值一样 就不会发出信号
//  只有两次数据不一样才会触发信号
    
    [[_textFiled.rac_textSignal distinctUntilChanged] subscribeNext:^(id x) {        
        NSLog(@"%@",x);        
    }];

  • take 取出信号 取出前几个信号
    // 1 创建信号
    RACSubject *signal = [RACSubject subject];
    
    // 2 处理信号 订阅信号的个数  如果订阅一个 只会接受第一个信号  subject 可以先订阅信号  在发送信号

    [[signal take:2] subscribeNext:^(id x) {       
        NSLog(@"%@",x);        
    }];
        
    [signal sendNext:@"1"];    
    [signal sendNext:@"2"];

  • takeLast 取最后N次的信号 前提条件订阅者必须调用完成 因为只有完成才知道总共有多少个信号
    RACSubject *signal = [RACSubject subject];
    // 取最后n次的信号    
    [[signal takeLast:2] subscribeNext:^(id x) {       
        NSLog(@"%@",x);        
    }];    
    [signal sendNext:@"1"];    
    [signal sendNext:@"2"];    
    [signal sendNext:@"3"];    
    [signal sendNext:@"4"];        
    // 必须调用完成  只用调用完成才能知道总共的信号量
    [signal sendCompleted];

  • takeUntil(RACSignal *)获取信号直到某个信号执行完成

    // 创建一个信号
    RACSignal *deallocSignal = [self rac_signalForSelector:@selector(viewWillDisappear:)];
    
    // 当deallocSignal信号发送的时候 就会移除通知
    [[[[NSNotificationCenter defaultCenter]rac_addObserverForName:UIKeyboardWillShowNotification object:nil] takeUntil:deallocSignal] subscribeNext:^(id x) {
        NSLog(@"键盘弹出%@",x);
    }];

  • skip:(NSUInteger):跳过几个信号 不接收
    RACSubject *signal = [RACSubject subject];
    
//   只会接收第二个信号    
    [[signal skip:1] subscribeNext:^(id x) {       
        NSLog(@"%@",x);        
    }];        
    [signal sendNext:@"我是信号一"];    
    [signal sendNext:@"我是信号二"];
   
1.5 ReactiveCocoa 操作方法之秩序
  • doNext 执行next之前会先执行这个block
  • doComplete 执行sendComplete就会调用这个方法
 
    
    [[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       
        [subscriber sendNext:@"我是奥卡姆剃须刀"];
        
        [subscriber sendCompleted];
        
        
        
        return nil;
        // 在执行订阅信号之前 会先执行这个方法
    }]doNext:^(id x) {
      
        NSLog(@"doNext--%@",x);
        
        // 信号完成后会调用这个方法
    }]doCompleted:^{
      
        NSLog(@"完成");
        
        // 订阅信号
    }] subscribeNext:^(id x) {
      
        NSLog(@"%@",x);
        
    }];

1.6 ReactiveCocoa 操作方法之时间
  • timeout: 超时 可以让一个信号在一定的时间后 自动报错

    [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
      
        [subscriber sendNext:@"123"];
        
        return nil;
        
        //  报错的时间是3秒
    }] timeout:3 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
               
        NSLog(@"subscribeNext-%@",x);                

// 3秒后 自动报错
    } error:^(NSError *error) {        

        NSLog(@"error-%@",error);        

    }];
  • interval: 定时 每隔一段时间就发出信号
    [[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(id x) {
       
        NSLog(@"%@",x);
        
    }];

  • delay 延迟发送next
    [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
       
        [subscriber sendNext:@"延迟两秒钟"];
        
        return nil;
        
    }] delay:2] subscribeNext:^(id x) {
      
        NSLog(@"%@",x);
        
    }];

1.7 ReactiveCocoa 操作方法之重复
  • retry 重试 只要失败 就一直执行信号中的block 直到成功
    __block int i = 0;
    
    [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {      
        if (i == 10) {
            [subscriber sendNext:@"123"];                        
        }else{            
            [subscriber sendError:nil];        
        }
        
        i++;
        
        return nil;
        
    }] retry ] subscribeNext:^(id x) {
       
        NSLog(@"subscribeNext--%@",x);
        
    }error:^(NSError *error) {
      
        NSLog(@"error--%@",error);
        
    }];

  • replay 重放 当一个信号被多次订阅 反复播放内容(没什么卵用)
    
    RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        
        [subscriber sendNext:@"123"];
        
        [subscriber sendNext:@"456"];
        
        return nil;
    }]replay];
   
    [signal subscribeNext:^(id x) {       
        NSLog(@"%@",x);        
    }];
    
    [signal subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容