当前位置: 首页 > news >正文

好玩的 RAC

  1. UIControl

    • 监听 control 点击
    • 从此告别 addTargetbtnClick
    [[self.loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(UIButton *btn) {
       // btn, 即 self.loginBtn
       // 这里执行点击之后的操作
    }];
    复制代码
  2. UITextField

    • 监听 textField 的 text 改变
    • 告别 UITextFieldDelegate
    [self.myTF.rac_textSignal subscribeNext:^(NSString* text) {
            
      // text 即 self.myTF.text 
      // 每当 text 有改变时,就会进入到这个 block 中
    }];
    复制代码
  3. UILabel

    • 把 label 的属性 text 绑定在 UITextField
    // self.myLab.text 随着 self.myTF.text 的改变而改变
    RAC(self.myLab, text) = self.myTF.rac_textSignal;   
    复制代码
  4. 监听属性改变

    • 一旦 person 的 name 有变化,就进入 block 里面
    • 再不用写繁琐的 KVO
    [RACObserve(self.per, name) subscribeNext:^(NSString *name)
    {
        // name 即 self.per.name
    }];
    复制代码
  5. 监听通知信息

    • 一旦键盘 frame 有所变化,就进入 block 里面

    • 内部已经进行通知释放,不需要再 dealloc 中 移除

    [[[[NSNotificationCenter defaultCenter] 
        rac_addObserverForName:UIKeyboardWillChangeFrameNotification object:nil] 
        // 这句不可少,表示 当 self 将要 dealloc 的时候,就要释放 通知
        takeUntil:self.rac_willDeallocSignal] 
        subscribeNext:^(NSNotification *notification) {
            NSLog(@"-----%@", notification.description);
    }];
    复制代码
    • 发送通知还是之前的办法
    [[NSNotificationCenter defaultCenter] postNotificationName:@"通知名称" object:nil];
    复制代码
  6. 数组

    • 遍历
    NSArray *array = @[@1, @2, @3, @4, @5];
    
    [array.rac_sequence.signal subscribeNext:^(id x) {
        // x 即 数组 array 的元素
     }];
    复制代码
    • 过滤 filter,并获取过滤后的数组
    NSArray *filter = [[array.rac_sequence filter:^BOOL(id value) {
       return  [value integerValue] > 2;
    }] array];
    复制代码
    • 匹配、映射 map,变换元素并获取新数组
    NSArray *map = [[array.rac_sequence map:^id(id value) {
            
       NSInteger a = [value integerValue] * [value integerValue];
       
       return [NSString stringWithFormat:@"%ld", a];
       
    }] array];
    复制代码
  7. 字典

    • rac_keySequencerac_valueSequence 跟数组一样
    • rac_sequence 需要 RACTupleUnpack 解包
    NSDictionary *dic = @{@"name": @"lion", @"age": @18};
    [dic.rac_sequence.signal subscribeNext:^(id x) {
       RACTupleUnpack(NSString *key, NSString *value) = x;
       
       NSLog(@"\r\nkey: %@\r\nvalue: %@", key, value);
    }];
    复制代码
  8. 最经典的登录界面,登录按钮是否可点击

    • 先联合两个信号
    • 再解析信号结果
    • 最后把结果绑定到信号上
    RAC(self.loginBtn, enabled) = [RACSignal 
                                      combineLatest:@[self.usernameTF.rac_textSignal, self.passwordTF.rac_textSignal] 
                                      reduce:^id(NSString *username, NSString *password){
                                          return @(username.length > 6 && password.length > 8);
                                  }];
    复制代码
  9. 节流 throttle

    • 表示 指定时间间隔内,不再发送信号
    • 这里添加 throttle, 表示在 0.5 秒内 text 没有改变时,才会进行搜索请求
    • 比如想搜索 reactiveCocoa,如果不添加 throttle,那么每输入一个字符,都会进行搜索请求,明显不是我们想要的。
    [[[self.searchTF rac_textSignal] 
        throttle:0.5] 
        subscribeNext:^(id x) {
            NSLog(@"开始搜索请求==%@", x);
    }];
    复制代码
  10. 一通组合拳:

  11. 判断用户名是否符合规则,

  12. 用户名正确之后,进行判断密码是否符合规则

  13. 密码正确,进行请求验证,成功之后返回请求结果

  14. 返回主线程根据结果更新界面 UI

// 1. 判断用户名
- (RACSignal *)validUsernameSignal {
 
 // 防止循环引用
 @weakify(self);
 // 因为返回的是一个信号,所以需要创建
 return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
     
     @strongify(self);
     
     [[[[[self.usernameTF rac_textSignal]
         // skip, 忽略,表示忽略几次信号
         // 这里两次分别是,首次加载的时候,和 TF 第一次响应的时候,
         // 可以把后面的 distinctUntilChanged 注释,测试下效果
         skip:2] 
        // map, 变换,把信号内容的类型变换为另一种类型
        // 把字符串根据长度转换为 bool 类型的对象
        map:^id(NSString *value) {
            return @(value.length > 5);
            // distinctUntilChanged 只有值不同时,才会发送信号
            // 这里为了防止,在值不满足/已满足 要求时,还继续发送信号
        }] distinctUntilChanged] 
      // 这里订阅的信息,就是转换后的 bool 类型的对象,非 1 即 0
      subscribeNext:^(id x) {
          if ([x integerValue] == 1) {
              [subscriber sendNext:@"用户名正确"];
              [subscriber sendCompleted];
              NSLog(@"-------用户名正确");
          } else {
              NSLog(@"-------用户名错误");
          }
          
          
      }];
     
     return nil; 
 }];
}

// 3. 请求验证
- (RACSignal *)loginSuccessSignalWithPassword: (NSString *)psw {
 
 
 return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
     
     /**
      * 这里可以进行请求验证用户名密码,并返回结果
      */
     NSString *str = @"用户信息 Data";
     NSLog(@"----登陆成功并返回用户信息 Data");
     
     NSDictionary *dic = @{@"data": str};
     
     [subscriber sendNext:dic];
     [subscriber sendCompleted];
     
     return nil;
 }];
}

// 2、4、密码验证和界面更新
- (void)loginResult {
 
 // 用户名的判断
 [[[[[[[self validUsernameSignal]
       // then, 只有前面的信号 发送信息,并完成才会继续
       // 下面进行 密码的判断
       then:^RACSignal *{
           return self.passwordTF.rac_textSignal;
       }] 
      // throttle,间隔 0.5 秒,
      // 防止在输入密码过程中不断发送信号,优化性能
      throttle:0.5] 
     // filter,过滤 ,只有符合要求的才能继续
     filter:^BOOL(NSString *value) {
         return [value length] > 6;
     }] 
    // flattenMap 根据源信号的内容生成新的信号,后续订阅、监听的就是新信号的内容
    // 常用于在信号嵌套中,处理信号中的信号
    // 这里使用 flattenMap 生成新的信号,并且在信号内发送登录结果信息,以便后续传递信息
    flattenMap:^RACStream *(NSString *value) {
        return [self loginSuccessSignalWithPassword:value];
    }]
   // deliverOn 切换线程,
   // RACScheduler, 即 RAC 中的多线程
   // 切换为主线程
   deliverOn:[RACScheduler mainThreadScheduler]] 
  // 订阅信号,获取信号传递的数据 data
  subscribeNext:^(id x) {
      NSLog(@"获取信息 \r\n%@,\r\n更新 UI", x);
  }];
}
复制代码

小结:

  • ReactiveCocoa 虽然说是思想上的巨大改变,但我更倾向于把它当做一种新型语法、更简便的语法来使用,在使用过程中,自然而然地就会体会它跟你以往编程的不同。使用多了,就会发现,原来这就是函数式响应式编程。

  • 语法上的使用,只是理解编程思想的入口,思想上的一小步才是编程上的一大步。

  • 理论是实践出来的,在你不懂理论的时候,那就赶紧实践吧。

相关文章:

  • Matlab2013a许可证过期问题,反复提示激活
  • 北京司法网拍首尝线下预展 海淀法院900万红木家具亮相京东秋拍
  • java进阶-常用数据结构以及算法思想
  • Nginx服务状态的监控
  • spring cloud Dalston.SR4 feign 实际开发中踩坑(二)
  • Kibana插件sentinl实现邮件报警
  • Vue slot分发内容
  • 前端面试总结(at, md)
  • Webpack入门之遇到的那些坑,系列示例Demo
  • Unity 微型调试器 Debugger
  • CSS文本超出省略
  • 黑客的滑铁卢——美国大断网全纪实
  • 继亚马逊之后,沃尔玛也开始建设无人超市
  • Unity SDK JDK 环境配置 避免各种莫名其妙的报错
  • Idea里面的postfix
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • ES2017异步函数现已正式可用
  • js算法-归并排序(merge_sort)
  • Promise面试题,控制异步流程
  • python 装饰器(一)
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 技术:超级实用的电脑小技巧
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 手写双向链表LinkedList的几个常用功能
  • 用jquery写贪吃蛇
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 智能网联汽车信息安全
  • Android开发者必备:推荐一款助力开发的开源APP
  • Java性能优化之JVM GC(垃圾回收机制)
  • python最赚钱的4个方向,你最心动的是哪个?
  • 选择阿里云数据库HBase版十大理由
  • ​ubuntu下安装kvm虚拟机
  • #鸿蒙生态创新中心#揭幕仪式在深圳湾科技生态园举行
  • #前后端分离# 头条发布系统
  • (第61天)多租户架构(CDB/PDB)
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (三)uboot源码分析
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)shell中括号的特殊用法 linux if多条件判断
  • ***linux下安装xampp,XAMPP目录结构(阿里云安装xampp)
  • ./configure,make,make install的作用(转)
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .NET 4.0中的泛型协变和反变
  • .net 按比例显示图片的缩略图
  • .NET 简介:跨平台、开源、高性能的开发平台
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .NET学习教程二——.net基础定义+VS常用设置
  • .考试倒计时43天!来提分啦!
  • @AliasFor注解
  • @RequestMapping用法详解
  • [codeforces]Checkpoints
  • [jquery]this触发自身click事件,当前控件向上滑出
  • [LeetCode]Multiply Strings
  • [Linux] Ubuntu install Miniconda