ReactiveCocoa 学习心得 -- 2

来源:互联网 发布:淘宝虚拟试衣间关了吧 编辑:程序博客网 时间:2024/05/28 23:22

在上一篇篇文章中,简单讲述了一下ReactiveCocoa集成到项目中的几种方法,环境已经具备,下面我们一起来接触一下RAC基本的几个用法

如下图所示:
现在有这样的一个需求,在输入框里没有文字的时候,输入框左边对应的文字为灰色,有文字的时候,变为黑色。并且当且仅当账号和密码都有输入的时候,登录按钮才能点击。
这里写图片描述

很常见的需求,第一反应我是这样的:

1,给两个输入框和两个label分别设置不同的tag值,根据textField的代理方法监听输入框里的内容,从而判断label的显示颜色。
2,设置一个变量初始值为0,当textField有值就+1,清空值就-1,然后kvo监听这个变量,当变量等于2的时候,loginButton可以点击,否则不可以点击。

或许你有更好的解决方案,也许你觉得代码还算简单。现在我们尝试着用RAC去解决

首先监听输入框的文字,看下面一段代码:

    [self.nameTextField.rac_textSignal subscribeNext:^(NSString *x) {        if (x.length>0) {            self.nameLabel.textColor = [UIColor blackColor];        }else{            self.nameLabel.textColor = [UIColor lightGrayColor];        }    }];    [self.passwordTextField.rac_textSignal subscribeNext:^(NSString *x) {        if (x.length>0) {            self.passwordLabel.textColor = [UIColor blackColor];        }else{            self.passwordLabel.textColor = [UIColor lightGrayColor];        }    }];

这里写图片描述
试下效果,竟然成功了。现在有了疑问,rac_textSignal是个什么东西,subscribeNext又是个什么东西?

rac_textSignal 属于RACSignal的一种,通常被称作为信号。你可以认为它是RAC封装好的一个信号(点进方法,你也会看到textViewDidChange的监听方法),用于监听输入框内文字的变化。


subscribeNext : block,可以理解为是信号的订阅。没有被订阅的信号,我们叫做冷信号,输入框文字发生变化后,不会触发任何动作。只有被订阅了,信号由冷变热,才能去处理一些事情。比如我们改变nameLabel 和 passwordLabel 的字体颜色 这件事情。

到这里,也许你会说,subscribeNext里面的一个大大的 if else 着实看着比较low, 和 rac_textSignal 比起来画风不太对。我们在看下面一种写法。

RAC(self.nameLabel, textColor) =[self.nameTextField.rac_textSignal map:^id(NSString *text) {        return text.length>0?[UIColor blackColor]:[UIColor lightGrayColor];    }];RAC(self.passwordLabel, textColor) = [self.passwordTextField.rac_textSignal map:^id(NSString *text) {        return text.length>0?[UIColor blackColor]:[UIColor lightGrayColor];     }];

不用怀疑,到达了一样的效果,这里又有了两个疑问,RAC 是什么, map又是什么?

RAC,是ReactiveCocoa的一个宏,它的功能是直接把输出的信号应用到该对象的属性上。这个宏有两个参数,第一个是对象,第二个是该属性名。


map 自然是去输出一个信号了,准确来说map更像一个信号转换器,把原始的信号(text) 转化为新的信号(color)。

这里写图片描述

如上图所示: map的作用就是把当前的信号转化为你想要的信号。


到这里, 需求已经实现了一大半了,下面就是如何利用RAC,去控制登录按钮的状态

同样,先看代码:

   RACSignal *nameValidSignal = [self.nameTextField.rac_textSignal map:^id(NSString *value) {       return @(value.length>0);   }];    RACSignal *passwordValidSignal = [self.passwordTextField.rac_textSignal map:^id(NSString *value) {        return @(value.length>0);    }];    [[RACSignal combineLatest:@[nameValidSignal,passwordValidSignal] reduce:^id(NSNumber *nameValid,NSNumber *passwordVaild){        return @([nameValid boolValue]&&[passwordVaild boolValue]);    }] subscribeNext:^(NSNumber *x) {        self.loginButton.backgroundColor = [x boolValue]?EnableColor:DisableColor;        self.loginButton.enabled = [x boolValue];    }];

从上面代码可以看出,我先创建了两个信号,使用map方法把这两个信号【输入的内容信号】 分别转化为 【 是否有文字输入的信号】(@0 或者 @1), 当这两个信号都得值都为(@1)的时候,登录键盘就可以点击了,否则就无法点击。

如何合并这两个信号呢?这里又引入了一个新的方法 combineLatest:reduce:

这里写图片描述

combineLatest 的作用是 把多个信号源合并到一起,并产生一个新的信号。
当这些信号源中任何一个发生变化,就会执行reduce下的block代码块。
并返回一个我们想要的全新的信号。

就像上面的代码一样,把 nameValidSignal(是否有姓名的信号) 和 passwordValidSignal (是否有密码的信号)这两个信号合并到一起,然后通过 reduce 返回一个新的信号 (登录按钮是否可以点击的信号),当然,这个信号还是冷信号,通过后面的 subscribeNext 让信号变成热信号,我们就可以拿到这个信号,去控制登录按钮的状态了。

当然,这个地方你也可以改写成

    RACSignal *signal = [RACSignal combineLatest:@[nameSignal,passwordsSignal] reduce:^id(NSNumber *nameValid,NSNumber *passwordVaild){        return  @([nameValid boolValue]&&[passwordVaild boolValue]);    }];    RAC(self.loginButton,backgroundColor) = [signal map:^id(id value) {        return [value boolValue]?EnableColor:DisableColor;    }];    RAC(self.loginButton,enabled) = [signal map:^id(id value) {        return value;    }];

RAC提供了很灵活的用法,试着用不同的方法去解决同一个问题,也是学习的一种方式。

到这里,登录的界面逻辑已经差不多了,下面的就是登陆的action了

[[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {        NSLog(@"Click Login Button");    }];

rac_signalForControlEvents 与上文 rac_textSignal 类似,都是RAC内部实现过的信号,我们只用把这个冷信号转化为热信号就好了。

总结:这篇博客主要记录了RAC里 rac_textSignal、rac_signalForControlEvents、subscribeNext:、RAC宏定义、map:、combineLatest:reduce的意义和实际用法。然而关于ReactiveCocoa,还有很多的东西值得我们探索和学习。保持进步,哪怕每天一点点。

1 0
原创粉丝点击