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<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);
  }];
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容