ReactiveCocoa入门

作者: 明月钓无痕 | 来源:发表于2016-08-10 18:26 被阅读95次

    ReactiveCocoa介绍

    ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的框架.是一个运用函数响应式编程(FRP)思想的框架.
    ReactiveCocoa为事件提供了很多处理方法,利用 RAC 可以很方便将要处理的事件和监听的事件代码放在一起,这样可以方便管理代码.使用 RAC 可以不需要考虑调用顺序,而是直接考虑结果.

    导入ReactiveCocoa

    这里我们使用 cocoapod进行导入.在 podfile 中添加

    pod 'ReactiveCocoa'
    

    ReactiveCocoa基础类

    在 RAC 中最常见的类是RACSignal.在RAC 中最重要的概念就是信号.

    1.RACSignal

    RACSiganl:只要有数据改变,就会把数据包装成一个信号传递出去.默认一个信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发。
    RACSubscriber: 订阅者,用于发送信号,这是一个协议,不是一个类,只要遵守这个协议,并且实现方法才能成为订阅者。通过create创建的信号,都有一个订阅者,帮助他发送数据。
    RACDisposable:用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。
    什么是冷热信号?
    冷热信号的概念源于.NET框架Reactive Extensions(RX)中的Hot Observable和Cold Observable,两者的区别是:

    1. Hot Observable是主动的,尽管你并没有订阅事件,但是它会时刻推送,就像鼠标移动;而Cold Observable是被动的,只有当你订阅的时候,它才会发布消息。
    2. Hot Observable可以有多个订阅者,是一对多,集合可以与订阅者共享信息;而Cold Observable只能一对一,当有不同的订阅者,消息是重新完整发送。
      这里面的Observables可以理解为RACSignal。
    RACSignal 的使用步骤:
    1. 创建信号: + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe;
    2. 订阅信号: - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock;
    3. 发送信号: - (void)sendNext:(id)value;
        // 创建信号
        RACSignal *singal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            // 发送信号
            [subscriber sendNext:@"发送信号"];
            return [RACDisposable disposableWithBlock:^{
                // 信号被取消订阅
                // 清空资源
                NSLog(@"取消订阅");
            }];
        }];
        // 订阅信号
        [singal subscribeNext:^(id x) {
            NSLog(@"%@", x);
            // 打印内容: "发送信号"
        }];
    

    2.RACSubject

    RACSubject:信号提供者,自己可以充当信号,又能发送信号。

    RACSubject使用步骤
    1. 创建信号: + (instancetype)subject; 跟RACSiganl不一样,创建信号时没有block
    2. 订阅信号: - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
    3. 发送信号: - sendNext:(id)value
        // 创建信号
        RACSubject *subject = [RACSubject subject];
        // 订阅信号
        [subject subscribeNext:^(id x) {
            NSLog(@"%@", x);
        }];
        // 发送信号
        [subject sendNext:@"subject发送信号"];
    

    3. RACReplaySubject

    RACReplaySubject:RACSubject的一个子类,用于保存发送过的值,当被订阅时,会向订阅者重新发送这些值。使用步骤和RACSubject类似.不同的是,RACReplaySubject可以先发送信号,再订阅信号.RACSubject不可以.

    ReactiveCocoa 集合类

    1.RACTuple

    RACTuple:元组.用于对数据的包装,( ps:对于使用过 swift 的人来说应该不陌生.)使用方法和数组类似

        RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"123", @"321"]];
        NSString *str = tuple[0];
        // str 的值是"123"
    

    2.RACSequence

    RACSequence:集合类,用于代替NSArray,NSDictionary,可以使用它来快速遍历数组和字典。

    1. 数组转化为集合类
        NSArray *arr = @[@"123", @"341", @"213"];
        // 将数组转化为集合
        RACSequence *squence = arr.rac_sequence;
        // 将集合转化为信号(遍历集合里的所有元素)
        [squence.signal subscribeNext:^(id x) {
            NSLog(@"%@", x);
        }];
    
    1. 字典转化为集合类
    NSDictionary *dict = @{@"name":@"明月钓无痕", @"age":@"26"};
      [dict.rac_sequence.signal subscribeNext:^(id x) {
          // 遍历所有的元素
          NSLog(@"%@", x);  // x 是元组类型,每一个键值对,包装成一个元组.
         // 用来解析元组的宏 RACTupleUnpack
          // 宏里面的参数 传需要解析的变量名
          // = 右边 放需要解析的元组
          RACTupleUnpack(NSString *key, NSString *value) = x;
          NSLog(@"%@--%@", key, value);
      }];
    

    ReactiveCocoa 事件处理类

    RACCommand:RAC中用于处理事件的类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程。
    使用步骤
    1.创建命令 initWithSignalBlock:(RACSignal * (^)(id input))signalBlock
    2.在signalBlock中,创建RACSignal,并且作为signalBlock的返回值
    3.执行命令 - (RACSignal *)execute:(id)input

    // 1. 创建命令
        RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
            // input: 执行命令时传入参数
            // 执行命令时调用 block
            NSLog(@"%@", input);
            // 2. 创建信号
            // 不能返回 nil. 如果要返回空信号使用 empty
            //   return [RACSignal empty];
            return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
                NSLog(@"====");
                [subscriber sendNext:@"请求数据"]; 
               // 数据传递完,最好调用sendCompleted,这时命令才执行完毕。
               [subscriber sendCompleted];
                return nil;
            }];
        }];    
        // 3. 执行命令
        RACSignal *signal = [command execute:@1];
        [signal subscribeNext:^(id x) {
            NSLog(@"x");
        }];
    

    使用场景:

    1. 在RAC开发中,通常会把网络请求封装到RACCommand,直接执行某个RACCommand就能发送请求。
    2. 当RACCommand内部请求到数据的时候,需要把请求的数据传递给外界,这时候就需要通过signalBlock返回的信号传递了。

    ReactiveCocoa 中常见的宏

    RAC(TARGET, ...): 给某个对象的某个属性绑定一个信号,只要信号内容改变,就会把内容赋值给属性
    RACObserve(TARGET, KEYPATH):监听某个对象的某个属性,返回的是信号.
    @weakify(Obj)和@strongify(Obj): 用于解决循环引用的问题
    RACTuplePack(...): 用于把数据包装成元组
    RACTupleUnpack(...):用于解析元组

    ReactiveCocoa 常见用法

    1. 代替代理:- (RACSignal *)rac_signalForSelector:(SEL)selector;
    2. 代替通知
      [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UITextFieldTextDidChangeNotification object:nil] subscribeNext:^(NSNotification *x) {
          
      }];
      // 监听文本
      [[self.userName rac_textSignal] subscribeNext:^(id x) {
          NSLog(@"%@", x);
      }];  
    
    1. 代替 KVO
    DZRedView *view = [[DZRedView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
      [self.view addSubview:view];
    // 需要手动包含头文件  #import <NSObject+RACKVOWrapper.h>
    //    [view rac_observeKeyPath:@"frame" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
    //        NSLog(@"%@, %@", value, change);
    //    }];
    //    view.x = 200;
    
      [[view rac_valuesAndChangesForKeyPath:@"frame" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld observer:nil] subscribeNext:^(id x) {
          NSLog(@"====%@", x);
      }];
      view.x = 100;
    
    1. 监听事件点击
      UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
      btn.backgroundColor = [UIColor redColor];
      [self.view addSubview:btn];
      [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
          NSLog(@"%@", x);
      }];
    

    相关文章

      网友评论

        本文标题:ReactiveCocoa入门

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