RAC的简单使用

新项目今天提测,项目中用到了RAC&MVVM框架,简单记录下RAC的简单使用

项目是OC开发,用的是ReactiveObjC库

RAC — ReactiveCocoa(RAC)  Github 上的一个开源函数响应编程框架!!

RAC里面最常见和常用的类

RACSignal  信号类

1.通过RACSignal创建一个信号 (默认是一个冷信号);

2.通过订阅者,订阅这个信号 (变成热信号);

3.发送信号

RACDisposable:它可以帮助我们取消订阅.

RACSubscriber(协议):订阅者(发送信号!)

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

RACReplaySubject: 可以先发送信号,再订阅,也可以先订阅再发送




RAC常用场景

可以代替代理

[[view rac_signalForSelector:@selector(btnclick:)] subscribeNext:^(RACTuple* _Nullablex) {

    }];

可以代替KVO

[[view rac_valuesForKeyPath:@"frame"observer:self] subscribeNext:^(id _Nullablex) {

 //x 是监听的属性改变的结果

 NSLog(@"%@",x);

    }];

监听事件

[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindofUIControl* _Nullablex) {

 NSLog(@"点击了");

    }];

代替通知

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {      

  NSLog(@"%@",x);    

}];

ps:虽然使用RAC代替通知可以免去手动移除通知的方法,但是又多了一步移除信号的操作.个人建议,用通知的话,还是用系统方法吧

监听文本框

[_tf.rac_textSignal subscribeNext:^(NSString * _Nullable x) {

        NSLog(@"%@",x);

    }];

用于监听 UITextField 和 UITextView 文本的改变,比写代理什么的,方便多了

定时器

self.disposable = [[RACSignal interval:1.f onScheduler:[RACScheduler scheduler]]subscribeNext:^(NSDate * _Nullable x) {

        //x是当前系统时间

        NSLog(@"%@",x);


        /* 关闭计时器 */

        [_disposable dispose];

    }];

ps:这个需要完成后关闭计时器

rac_liftSelector  适用于处理多个请求,都返回结果之后,刷新UI

RACSignal * signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {

        NSLog(@"1111");

        [subscriber sendNext:@"数据1"];

        return nil;

    }];

    RACSignal * signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {

        NSLog(@"2222");

        [subscriber sendNext:@"数据2"];

        return nil;

    }];

[self rac_liftSelector:@selector(setupData::) withSignalsFromArray:@[signal1,signal2]];

使用注意事项:

几个信号,selector的方法就几个参数,每个参数对应信号发出的数据。

不需要主动订阅,内部会主动订阅

RACMulticastConnection  信号连接类,适用于一个信号有多个订阅者

RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {

        [subscriber sendNext:@"请求到的数据"];

        returnnil;

    }];

    RACMulticastConnection* connection = [signal publish];

    [connection.signal subscribeNext:^(id  _Nullablex) {

        NSLog(@"订阅的信号%@-----1",x);

    }];

    [connection.signal subscribeNext:^(id  _Nullablex) {

        NSLog(@"订阅的信号%@-----2",x);

    }];

    [connection connect];

RACCommand 创建命令

RACCommand* command = [[RACCommandalloc]initWithSignalBlock:^RACSignal*_Nonnull(id  _Nullableinput) {

        //input:指令  就是下边execute: 传的参数

        return [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {

            [subscriber sendNext:@"发送的数据"];

            //发送完成  写上命令才会监听到执行完毕

            [subscribersend Completed];

            returnnil;

        }];

    }];

    //监听有没有执行完毕

    [command.executing subscribeNext:^(NSNumber*_Nullablex) {

        if([x boolValue]){//正在执行!!

            NSLog(@"正在执行!!");

        }else{

            NSLog(@"已经结束或还没开始做");

        }

    }];

[command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {

        NSLog(@"订阅-----%@",x);//这里就是上边发送的数据

    }];



RAC常用的宏

给某个对象的某个属性绑定信号,一旦信号产生数据,就会将内容赋值给属性!

    RAC(_label,text) = _textF.rac_textSignal;

只要这个对象的某个属性发生变化  类似KVO

    [RACObserve(self.label,text)subscribeNext:^(id  _Nullablex) {

        NSLog(@"%@",x);

    }];

包装元祖

    RACTuple* tuple =RACTuplePack(@"1",@"2");

解包

    RACTupleUnpack(NSString * str) = tuple;

解决循环引用问题  需要配套使用

    @weakify(self);

    @strongify(self);



RAC过滤

filter 过滤条件  筛选不通过的值

[[_textField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {

        //value:源信号的内容

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

        return [value length] >5;

        //返回值:就是过滤条件,只有满足这个条件,才能获取到内容

    }]subscribeNext:^(NSString*_Nullablex) {

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

    }];

ignore 忽略一些值!! 一次只能忽略一个对象

RACSubject * subject = [RACSubject subject];

  [[[subject ignore:@"ahaha"] ignore:@"1234"]subscribeNext:^(id  _Nullablex) {

        NSLog(@"%@",x);

    }];

take\takeLast  拿出前边几条数据或者后边几条数据

    RACSubject* subject = [RACSubject subject];

    [[subject takeLast:3]subscribeNext:^(id  _Nullablex) {

        NSLog(@"%@",x);

    }];

take:指定拿前面的哪几条数据!!(从前往后)  根据发送数据的前几条

takeLast: 取出发送的数据中 后面几条数据   ps: 必须调发送结束的方法后才会有数据返回

takeUntil  标记信号  取出数据 直到标记的信号发送数据截止

RACSubject * subject = [RACSubject subject];

    //标记信号

    RACSubject* tagSubject = [RACSubjectsubject];

    [[subjecttakeUntil:tagSubject]subscribeNext:^(id  _Nullablex) {

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

    }];

distinctUntilChanged 忽略掉重复数据

   RACSubject * subject = [RACSubject subject];

    [[subjectdistinctUntilChanged] subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }];

skip  按照发送数据的顺序略过几个值

    RACSubject * subject = [RACSubject subject];

    [[subjectskip:2]subscribeNext:^(id  _Nullablex) {

        NSLog(@"%@",x);

    }];

RAC遍历字典或者数组

遍历数组

[arr.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

        NSLog(@"%@",x);

    }];

遍历字典

[dic.rac_sequence.signal subscribeNext:^(id  _Nullable x) {

        //这里x是元组,每个元组中包含字典的一对键值对 x[0]为key  x[1]为value

        RACTupleUnpack(NSString * key,NSString * value) = x;

        NSLog(@"%@---%@",key,value);

    }];

组合信号

 concat  按顺序组合

    RACSubject* subject1 = [RACSubject subject];

    RACSubject* subject2 = [RACSubject subject];

    RACSubject* subject3 = [RACSubject subject];

    //订阅信号

    [[RACSignal concat:@[subject1,subject2,subject3]]subscribeNext:^(id  _Nullablex) {

        NSLog(@"%@",x);

    }];

ps: subject1 发送结束才会接受 subject2,依次类推

merge  组合信号  根据发送的情况接收数据,与数组中的顺序没有关系,哪个先发送就先收到哪个

    RACSubject* subject1 = [RACSubject subject];

    RACSubject* subject2 = [RACSubject subject];

    RACSubject* subject3 = [RACSubject subject];

    RACSignal* signal = [RACSignal merge:@[subject2,subject3,subject1]];

    [signalsubscribeNext:^(id  _Nullablex) {

        //任意一个信号发送内容就会来这个Block

        NSLog(@"%@",x);

    }];

zipWith : 两个信号压缩!只有当两个信号同时发出信号内容,并且将内容合并成为一个元组

    RACSubject* subject1 = [RACSubject subject];

    RACSubject* subject2 = [RACSubject subject];

    [[subject1 zipWith:subject2]subscribeNext:^(id  _Nullablex) {

        //只有两个信号都发送数据  才会来到这里  少一个不行

       //比如,subject1 发送了一个字符串@"1",又发送了一个字符串@"2",这时subject2才发送一个字符串@"a",那么这里过来的是@"2"和@"a"组成的元组

        NSLog(@"%@",x);

    }];



RAC个人感觉配合MVVM使用更方便些

比如,在 viewModel 中请求数据/处理数据, VC中订阅信号即可

viewModel 中

        @weakify(self);

        _parseCommand= [[RACCommand alloc] initWithSignalBlock:^RACSignal*_Nonnull(id  _Nullableinput) {

            return [RACSignal createSignal:^RACDisposable*_Nullable(id  _Nonnullsubscriber) {

                @strongify(self);

                [Network postRequestWithApi:api param:nil result:^(id data) {

                         [subscriber sendNext:self.dataArr];

                        [subscriber sendCompleted];

                }];

                return nil;

            }];

        }];

    }

VC中

@weakify(self);

    [self.viewModel.parseCommand.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {

        @strongify(self);

    }];

    [self.viewModel.parseCommand execute:param];

或者

viewModel中

- (RACSignal*)signalForSearchOrgWithName:(NSString*)orgName

{

    @weakify(self);

    RACSignal * signal = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {

        @strongify(self);

      [subscriber sendNext:self.orgDataArr];  

      [subscriber sendCompleted];      

        return nil;

    }];

    return signal;

}

然后在VC中调用订阅



在tableview的cell使用,需要注意复用的问题

@weakify(self);

    [[[photoCell.photographBtn rac_signalForControlEvents:UIControlEventTouchUpInside] takeUntil:photoCell.rac_prepareForReuseSignal] subscribeNext:^(__kindof UIControl * _Nullable x) {

        @strongify(self);

    }];

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

推荐阅读更多精彩内容