IOS知识积累

iOS - RAC(ReactiveObjC)的简单介绍

2019-09-27  本文已影响0人  ShIwEn9

本编文章是我对 MVVM + RAC 知识的一些学习总结了分享,如错误的地方,希望可以各位大佬积极指正。⛽️
文章中引用了别人文章中很多的内容,在这里说明一下侵权删。
打一个广告:本人目前离职状态(公司资金出现问题,原部门人员全体被迫离职。。。)如果有对我感兴趣的请给我留言或者简书私聊我,谢谢 !

ReactiveCocoa

在学习RAC之前我们得了解一下什么是响应式编程(FRP: functional reactive programming 翻墙),因为RAC就是通过 函数式 + 响应式编程相结合实现的。

🌰 在我们编写代码的时候如:a = b + c 当我们更改 b 或 c 的时候,a 的值并不会立即改变,最起码你得重写运行一次代码才行,但是在响应式编程的世界里面,我们 改变 b 或者 c 的时候,a 的值也会发生改变,这就意味着它们之间出现了一只绑定的关系。是不是很神奇。。。。。。

一、配置RAC

在实际使用中,我们并不是直接查询ReactiveCocoa,它其实是一个总称,在ReactiveCocoa中分为Swift版的 ReactiveSwift和OC版本的
ReactiveObjC,这里我介绍的是ReactiveObjC部分。
使用cocoaPods在podfile中添加

 pod 'ReactiveObjC', '~> 3.1.0' //或者 pod 'ReactiveObjC'

然后pod install一下。在项目中#import <ReactiveObjC.h>,建议放入pch头文件中。

二、RAC的一些简单介绍

RAC的一个主要优点是,它提供了处理异步行为的单一、统一的方法,包括委托方法、回调块、目标操作机制、通知和kvo

1. 基本类的使用
// RACSignal的使用
-(void)RACSignal {
    // 1.创建signal信号
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSLog(@"%@",subscriber);
        // subscriber并不是一个对象
        // 3. 发送信号
        [subscriber sendNext:@"123"];
        
        // 4. 完成订阅
        [subscriber sendCompleted];
        
        // 4. 销毁信号
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"销毁了");
        }] ;
    }];
    
    // 2.1订阅
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    // 2.2 针对实际中可能出现的逻辑错误,RAC提供了订阅error信号
    [signal subscribeError:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];
}

RACSignal 是一个信号类,只要有数据改变就会把数据包装成信号传递出去,但是注意发出信号的并不是 RACSignal 它不可以发送信号,发送信号的是 订阅者 subscriber ,并把nextBlock保存到订阅者里面,创建的时候会返回 [RACDynamicSignal createSignal:didSubscribe];调用RACDynamicSignal的didSubscribe,发送信号[subscriber sendNext:value],拿到订阅者的nextBlock调用。


// RACSubject(可自己发送信号也可以自己充当信号)
- (void)initRACSubject {
    /*
     1.创建RACSubject信号
     2.订阅信号(subscribeNext)。本质就是创建订阅者,把订阅者放到数组里面。
     3.发送信号(sendNext)。本质就是让订阅者数组里面的每一个订阅者都去调用 sendNext 方法。
     */
    
    RACSubject *subject = [RACSubject subject];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"RACSubjectTest x = %@",x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    } completed:^{
        NSLog(@"11111");
    }];
    //发送信号
    [subject sendNext:@"信号🍺🍺🍺🍺🍺🍺🍺"];
}

RACSubject最大的优点就是自己可以发送和接收信息,同时它是RACSignal的子类。在公司的项目我发现很多的时候都会用RACSubject来代替RACSignal作为返回值。

// RACReplaySubject
-(void)initRACReplaySubject{
    // 1.1创建方法一
    RACReplaySubject *repSubject = [RACReplaySubject subject];
    
    // 1.2创建方法二: 通过设置capacity来限定它接收事件的数量
    RACReplaySubject *repSubject2 = [RACReplaySubject replaySubjectWithCapacity:2];
    
    // 2发送
    [repSubject sendNext:@"repSubject"];
    
    // 这里限制了repSubject2的最大接受事件为2 所以第一个会被移除
    [repSubject2 sendNext:@"repSubject2"];
    [repSubject2 sendNext:@"repSubject22"];
    [repSubject2 sendNext:@"repSubject222"];
    
    // 3订阅
    [repSubject subscribeNext:^(id  _Nullable x) {
        NSLog(@"repSubject = %@",x);
    }];
    
    [repSubject2 subscribeNext:^(id  _Nullable x) {
        NSLog(@"repSubject2 = %@",x);
    }];
}

RACReplaySubject作为RACSubject的子类自然会拥有父类的所有特性,同时它也有自己的特性,比如我们通过 replaySubjectWithCapacity 去创建RACReplaySubject那么就会限制它接收时间的数量。在它的内部,通过遍历来实现限制功能。

// RACTuple(元组)-- 其内部就是封装了数组,用起来跟数组差不多
-(void)initRACTuple{
    //1.创建
    // 1.1 通过定值创建RACTuple
    RACTuple *tuple = [RACTuple tupleWithObjects:@"1",@"2",@"3", nil];
    
    // 1.2 利用 RAC 宏快速封装
    RACTuple *tuple2 = RACTuplePack(@"1", @"2", @"3");
    
    // 1.3 从别的数组中获取内容
    RACTuple *tuple3 = [RACTuple tupleWithObjectsFromArray:@[@"1",@"2",@"3"]];
    
    // 添加某个值
    [tuple tupleByAddingObject:@"123"];
    NSLog(@"tupleByAddingObject = %@", tuple);
    
    // 根据下标获取
    NSLog(@"tuple objectAtIndex:2 = %@",[tuple objectAtIndex:2]);
    
    // 取出所有的值
    NSLog(@"[tuple2 allObjects] = %@",[tuple2 allObjects]);
    
    NSLog(@"元组-->%@", tuple3[0]);
    NSLog(@"第一个元素-->%@", [tuple3 first]);
    NSLog(@"最后一个元素-->%@", [tuple3 last]);
}

其内部也实现了一些方法,在例子中都有展示。

//RACCommand
-(void)RACCommand{
    /*
     command 命令
     可以监听信号的状态等,可以在订阅/执行(即 excute:方法)时传递参数。因此当需要向信号传递参数的时候,RACComand 更好用
     RACCommand 包含了一个 executionSignal 的信号,这个信号是对用户透明的,它是自动创建的,由 RACCommand 进行管理。许多资料中把它称之为信号中的信号,是因为这个信号会发送其它信号——即 RACCommand 在初始化的 signalBlock 中创建(return)的信号。这个信号是 RACCommand 创建时由我们创建的,一般是用于处理一些异步操作,比如网络请求等。
     RACCommand 的另一个优点了,它可以监听 RACCommand 自身的执行状态,比如开始、进行中、完成、错误等。用 RACSignal 可以监听到完成(complete)、错误(error)、进行中(next)。但开始就无法实现了.
     */
    //NSString *input = @"执行";
    
    RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
        // execute发送的值
        NSLog(@"input = %@",input);
        
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            
            // RACSignal 发出信号
            [subscriber sendNext:@"RACSignal : 我是谁,我在哪?"];
            [subscriber sendCompleted];
            return [RACDisposable disposableWithBlock:^{
                // block调用时刻:当信号发送完成或者发送错误,就会自动执行这个block,取消订阅信号。
                // 执行完Block后,当前信号就不再被订阅了。
                // 信号销毁的时候 会执行这个闭包
                // 用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。
                // 使用场景:不想监听某个信号时,可以通过它主动取消订阅信号。
                NSLog(@"signal1销毁了");
            }];
        }];
    }];
    
    //订阅外层信号(即 executionSignals)。外层信号在订阅或执行(即 execute: )时发送。因此我们可以将它视作请求即将开始之前的信号;
    //订阅内层信号,因为内层信号由外层信号(executionSignals)作为数据发送(sendNext:),而发送的数据一般是作为 subcribeNext:时的 block 的参数来接收的,因此在这个块中,块的参数就是内层信号。这样我们就可以订阅内层信号了
    // executionSignals就是用来发送信号的信号源,需要注意的是这个方法一定要在执行execute方法之前,否则就不起作用了
    [command.executionSignals subscribeNext:^(RACSignal *_Nullable x) {
        [x subscribeNext:^(id  _Nullable x) {
            NSLog(@"executionSignals-->subscribeNext-->%@",x);
        }];
        NSLog(@"executionSignals - x = %@",x);
    }];
    
    /*
      获取信号中信号最近发出信号,订阅最近发出的信号
      注意switchToLatest:只能用于信号中的信号
     */
    [[command.executionSignals switchToLatest] subscribeNext:^(id  _Nullable x) {
        NSLog(@"switchToLatest-->%@",x);
    }];
    // 写法二 用点语法
//    [command.executionSignals.switchToLatest subscribeNext:^(id  _Nullable x) {
//        <#code#>
//    }];
    
    // 监听信号是否执行完毕
    [[command.executing skip:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"executing-->%@",x);
        if ([x boolValue]) {
            NSLog(@"正在执行");
        }else{
            NSLog(@"执行完毕");
        }
    }];
    
    //RACCommand 比较特殊的一点是 error 信号需要在 errors 中订阅,而不能在 executionSignals 中订阅。在这里我们订阅了 errors 信号,并修改 data、error 和 requestStatus 属性值。
    [command.errors subscribeNext:^(id  _Nullable x) {
        NSLog(@"errors-->%@",x);
    }];
    
    //开始执行
    [command execute:@"起飞了"];
    
}

简单来说就是对信号进行管理和监听。

2. RAC定义的常用方法
// 点击事件用RAC实现
- (void)RACButton_targetAction {
// 按钮的点击事件
    [[self.testButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        NSLog(@"RAC按钮点击了");
        NSLog(@"%@",x);
    }];
// tap 点击事件
    self.testLable.userInteractionEnabled = YES;
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
    [self.testLable addGestureRecognizer:tap];
    [tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
        //点击事件响应的逻辑
        NSLog(@"RAC的Label点击了");
        NSLog(@"%@",x);
    }];
}
- (void)RAC_KVO {
    //1
    [RACObserve(self.testLable, text) subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    //2
    [RACObserve(self.testTextField, text) subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    } completed:^{
        NSLog(@"success");
    }];
}
// RAC实现代理
- (void)RACTextFieldDelegate {
    [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] subscribeNext:^(RACTuple * _Nullable x) {
        NSLog(@"textField delegate == %@",x);
    }];
    self.testTextField.delegate = self;
}
// RAC实现通知
- (void)RACNotification {
    [[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidHideNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        NSLog(@"%@",x);
    }];
}
- (void)RACTimer {
    //主线程中每两秒执行一次
    [[RACSignal interval:2.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
        NSLog(@"%@",x);
    }];
    //创建一个新线程
    [[RACSignal interval:1 onScheduler:[RACScheduler schedulerWithPriority:(RACSchedulerPriorityHigh) name:@" com.ReactiveCocoa.RACScheduler.mainThreadScheduler"]] subscribeNext:^(NSDate * _Nullable x) {
        
        NSLog(@"%@",[NSThread currentThread]);
    }];
}
- (void)RACSequence {
    //遍历数组
    NSArray *racAry = @[@"rac1",@"rac2",@"rac3"];
    [racAry.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    //遍历字典
    NSDictionary *dict = @{@"name":@"dragon",@"type":@"fire",@"age":@"1000"};
    [dict.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        RACTwoTuple *tuple = (RACTwoTuple *)x;
        NSLog(@"key == %@, value == %@",tuple[0],tuple[1]);
    }];
}
3. 相关函数的使用
- (void)FlattenMap {
    // flattenMap
    [[self.testTextField.rac_textSignal flattenMap:^__kindof RACSignal * _Nullable(NSString * _Nullable value) {
        //自定义返回内容
        return [RACReturnSignal return:[NSString stringWithFormat:@"flattenMap 自定义了返回信号:%@",value]];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"x = %@",x);
        NSLog(@"%@",NSStringFromClass([x class]));
    }];
}
// map 和 flattenMap 映射
- (void)map {    
    [[self.testTextField.rac_textSignal map:^id _Nullable(NSString * _Nullable value) {
        return [NSString stringWithFormat:@"map 自定义了返回信号:%@",value];
    }] subscribeNext:^(id  _Nullable x) {
        NSLog(@"x = %@",x);
        NSLog(@"%@",NSStringFromClass([x class]));
    }];
}

同样作为映射命令,在实际开发过程中,如果使用map命令,则block代码块中return的是对象类型;而flattenMap命令block代码块中return的是一个新的信号。

-(void)RACSkip{
    RACSubject *subject = [RACSubject subject];
    
    [[subject skip:1] subscribeNext:^(id  _Nullable x) {
        NSLog(@"skip = %@",x);
    }];
    
    [subject sendNext:@"12"];
    [subject sendNext:@"123"];
    [subject sendNext:@"1234"];
    
}

得到的信号值 只有 123 和 1234,在开发中经常会用它来过滤第一个原始值。

- (void)RACfilter {
    @weakify(self);
    [[self.testTextField.rac_textSignal filter:^BOOL(NSString * _Nullable value) {
        //过滤判断条件
        @strongify(self)
        if (self.testTextField.text.length >= 6) {
            self.testTextField.text = [self.testTextField.text substringToIndex:6];
            self.testLable.text = @"已经到6位了";
            self.testLable.textColor = [UIColor redColor];
        }else{
            self.testLable.text = @"最多输入6位数";
            self.testLable.textColor = [UIColor greenColor];
        }
        return value.length <= 6;
        
    }] subscribeNext:^(NSString * _Nullable x) {
        //订阅逻辑区域
        NSLog(@"filter过滤后的订阅内容:%@",x);
    }];
}
// ignore实现过滤
- (void)ignoreValue {
   [[self.testTextField.rac_textSignal ignoreValues] subscribeNext:^(id  _Nullable x) {
       //将self.testTextField的所有textSignal全部过滤掉
       NSLog(@"过滤后%@",x);
   }];
   
   [[self.testTextField.rac_textSignal ignore:@"1"] subscribeNext:^(id  _Nullable x) {
       //将self.testTextField的textSignal中字符串为指定条件的信号过滤掉
       NSLog(@"过滤 1 后%@",x);
   }];
}
- (void)distinctUntilChanged {
    // 第一种:不做distinctUntilChanged限制的
    // 1. 创建
    RACSubject *subject = [RACSubject subject];
    
    // 2.1订阅
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"RACSubjectTest x = %@",x);
    } error:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    } completed:^{
        NSLog(@"11111");
    }];
    //3.发送信号
    [subject sendNext:@"信号🍺🍺🍺🍺🍺🍺🍺"];
    [subject sendNext:@"信号🍺🍺🍺🍺🍺🍺🍺"];
    
    
    //第二种:通过 distinctUntilChanged 方法来 判断前面信号的值是否和当前的相同,如果相同就不会去接受信号
    // 1. 创建
    RACSubject *subject2 = [RACSubject subject];
    // 2.1订阅
    [[subject2 distinctUntilChanged] subscribeNext:^(id  _Nullable x) {
        NSLog(@"RACSubjectTest distinctUntilChanged x = %@",x);
    }];
    // 2.2错误
    [subject subscribeError:^(NSError * _Nullable error) {
        NSLog(@"error = %@",error);
    }];
    
    // 3.发送
    [subject2 sendNext:@"信号🍺🍺🍺🍺🍺🍺🍺"]; // 1
    [subject2 sendNext:@"信号🍺🍺🍺🍺🍺🍺🍺"]; // 2
    [subject2 sendNext:@"信号🍺🍺🍺"];          // 3
}

打印的结果只有 1 、3

-(void)RACConcat{
    // 创建信号1
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"A123"];
        //一定要执行sendCompleted,不然永远都不会执行请求B
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"A 销毁了");
        }];
    }];
    
    [signalA subscribeNext:^(id  _Nullable x) {
        NSLog(@"A = %@",x);
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"B1234"];
        //一定要执行sendCompleted,不然永远都不会执行请求B
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"B 销毁了");
        }];
    }];
    
    [signalB subscribeNext:^(id  _Nullable x) {
        NSLog(@"B = %@",x);
    }];
    
    // concat:按照顺序去连接,先执行请求A,再去执行请求B
    RACSignal *concatSignal = [signalA concat:signalB];
    // 订阅组合信号
    [concatSignal subscribeNext:^(id  _Nullable x) {
        // 既能拿到A信号的值,又能拿到B信号的值
        NSLog(@"A和B = %@",x);
    }];
}
 /*
     2019-09-04 12:06:50.773126+0800 ReactiveObjc[3070:463032] A = A123
     2019-09-04 12:06:50.773196+0800 ReactiveObjc[3070:463032] A 销毁了
     2019-09-04 12:06:50.773226+0800 ReactiveObjc[3070:463032] B = B1234
     2019-09-04 12:06:50.773241+0800 ReactiveObjc[3070:463032] B 销毁了
     2019-09-04 12:06:50.773550+0800 ReactiveObjc[3070:463032] A和B = A123
     2019-09-04 12:06:50.773572+0800 ReactiveObjc[3070:463032] A和B = B1234
     2019-09-04 12:06:50.773585+0800 ReactiveObjc[3070:463032] B 销毁了
     2019-09-04 12:06:50.773595+0800 ReactiveObjc[3070:463032] A 销毁了
     */
-(void)RACThen{
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        // 发送信息
        [subscriber sendNext:@"signalA"];
        // 发送完成,不然接受不到B的数据
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signalA dealloc");
        }];
    }];
    
    [signalA subscribeNext:^(id  _Nullable x) {
        NSLog(@"signalA = %@",x);
    }];
    
    RACSignal *signalB = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        // 发送信息
        [subscriber sendNext:@"signalB"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signalB dealloc");
        }];
    }];
    
    [signalB subscribeNext:^(id  _Nullable x) {
        NSLog(@"signalB = %@",x);
    }];
    // 利用then组合信号
    // then:会忽略掉 A 信号的所有值 之后再去接收 B 的值
    RACSignal *thenSignal = [signalA then:^RACSignal * _Nonnull{
        // 返回 B 的信号
        return signalB;
    }];
    
    [thenSignal subscribeNext:^(id  _Nullable x) {
        NSLog(@" signalB = %@",x);
    }];
    
    /*
     2019-09-04 13:57:00.316571+0800 ReactiveObjc[3551:500030] signalA = signalA
     2019-09-04 13:57:00.316647+0800 ReactiveObjc[3551:500030] signalA dealloc
     2019-09-04 13:57:00.316692+0800 ReactiveObjc[3551:500030] signalB = signalB
     2019-09-04 13:57:00.316714+0800 ReactiveObjc[3551:500030] signalB dealloc
     2019-09-04 13:57:00.318309+0800 ReactiveObjc[3551:500030]  x = signalB
     2019-09-04 13:57:00.318333+0800 ReactiveObjc[3551:500030] signalB dealloc
     2019-09-04 13:57:00.318349+0800 ReactiveObjc[3551:500030] signalA dealloc
     */
}
-(void)RACMerge{
    RACSubject *subjectA = [RACSubject subject];
    
    RACSubject *subjectB = [RACSubject subject];
    
    RACSignal *merge = [subjectA merge:subjectB];
    
    // 订阅信号
    [merge subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    // 任何一个信号有新的值的时候就会调用,谁先发请求谁先响应
    [subjectA sendNext:@"发送A请求"];
    [subjectB sendNext:@"发送B请求"];
    /*
     2019-09-04 14:13:10.027433+0800 ReactiveObjc[3574:503914] 发送A请求
     2019-09-04 14:13:10.027487+0800 ReactiveObjc[3574:503914] 发送B请求
     */
}
-(void)RACZipWith{
    RACSubject *subjectA = [RACSubject subject];
    
    RACSubject *subjectB = [RACSubject subject];
    
    RACSignal *zipWith = [subjectA zipWith:subjectB];
    
    [zipWith subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    // RACTwoTupl继承自 RACTuple RACTuple 类似于数组
    [zipWith subscribeNext:^(RACTwoTuple *  _Nullable x) {
        NSLog(@"%@",[x objectAtIndex:0]);
    }];
    //只有当两个请求都发送请求之后才会触发回调事件
    [subjectB sendNext:@"send B request"];
    [subjectA sendNext:@"send A request"];
    
    //上面我们明明就是先调用 signalB 的sendNext 方法,但回调打印的却是signalA在前面。这是为什么?因为我们在组合信号的时候 [signalA zipWith:signalB],我们把signalA放前面,所以回调的时候它也会放在前面。
    /*
     <RACTwoTuple: 0x28252bb20> (
     "send A request",
     "send B request"
     )
     */
}
🌰
-(void)combineLatestAndReduce{
    
    CGFloat width = self.view.bounds.size.width;
    //账号
    UITextField *tf1 = [[UITextField alloc]initWithFrame:CGRectMake(width / 2.0 - 100, 380, 200, 40)];
    tf1.placeholder = @"请输入账号";
    tf1.backgroundColor = [UIColor colorWithRed:0.0f green:0.5f blue:0.8f alpha:1.0f];
    [self.view addSubview:tf1];
    //密码
    UITextField *tf2 = [[UITextField alloc]initWithFrame:CGRectMake(width / 2.0 - 100, 450, 200, 40)];
    tf2.placeholder = @"请输入密码";
    tf2.backgroundColor = [UIColor colorWithRed:0.0f green:0.5f blue:0.8f alpha:1.0f];
    [self.view addSubview:tf2];
    
    
    //登陆按钮
    UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(width / 2.0 - 100, 580, 200, 40);
    [button setTitle:@"登录" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    button.titleLabel.font = [UIFont systemFontOfSize:15];
    [button setBackgroundColor:[UIColor greenColor]];
    //@weakify(self);
    [[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        //@strongify(self);
        NSLog(@"登录");
    }];
    [self.view addSubview:button];
    
    //组合信号
    // 第一个参数:组合哪些信号
    // 第二个参数:reduce 聚合
    // 注意,reduce是一个block,它看起来好像没参数,但其实它的参数是由我们自己来决定的,我们可以自己去修改
    // reduce 参数: 跟组合的信号有关,一一对应,你有几个信号,就有几个参数,所以我们在下面加上(NSString *account, NSString *pwd)
    // reduce 参数类型: 组合的信号发送的是什么类型,参数就是什么类型
    RACSignal *combineSignal = [RACSignal combineLatest:@[tf1.rac_textSignal,tf2.rac_textSignal] reduce:^id _Nullable(NSString *account, NSString *pwd){
        // block调用: 只要任意一个源信号发送内容就会调用,组合成一个新的值
        return @(account.length && pwd.length);
    }];
    
//    [combineSignal subscribeNext:^(id  _Nullable x) {
//        NSLog(@"%@",x);
//        button.enabled = [x boolValue];
//    }];
    
    
    //上面的写法其实可以换成下面这种,更简单明了
    // RAC 用于给某个对象的某个属性绑定
    RAC(button,enabled) = combineSignal;
}

到这里,RAC的一些基本使用就介绍完了,当然知其然要知其所以然,阅读源码,了解人家实现的思路才是王道。各位骚年们,我们一起努力吧!!⛽️

上一篇下一篇

猜你喜欢

热点阅读