ReactiveCocoa入门

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 subscriber))didSubscribe;
  2. 订阅信号: - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock;
  3. 发送信号: - (void)sendNext:(id)value;
    // 创建信号
    RACSignal *singal = [RACSignal createSignal:^RACDisposable *(id 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 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 
//    [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入门)