ReactiveCocoa是什么
ReactiveCocoa(简称为RAC),响应式框架,是由Github开源的一个应用于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。
在我们iOS开发过程中,经常会响应某些事件来处理某些业务逻辑,例如按钮的点击,上下拉刷新,网络请求,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation)。但是这些事件都用不同的方式来处理,比如action、delegate、KVO、callback(回调)等。
其实这些事件,都可以通过RAC处理,ReactiveCocoa为事件提供了很多处理方法,而且利用RAC处理事件很方便,可以把要处理的事情,和监听的事情的代码放在一起,这样非常方便我们管理,就不需要跳到对应的方法里。非常符合我们开发中高聚合,低耦合的思想。
这个框架能为我们带来什么样的便利
能使业务逻辑变得更加清晰
大量减少开发代码量
大量使用block块
什么时候能用到这个RAC呢
当你需要用到代理的时候开始使用它。例如用RAC检测textfiled的实时输入,不需要繁琐的遵守协议、挂代理、实现方法
涉及到点击事件的时候可以用,不需要再addtarget及实现方法。
还有通知、KVO、回调等。
具体怎么使用
创建一个新项目,使用Cocoapods在项目中导入该框架。将下面的代码复制到Podfile文件然后更新。
use_frameworks!
pod 'ReactiveCocoa', '~> 4.0.4-alpha-4'
PS:因为这个框架是采用Swift和OC混编的,所以在Podfile文件的最上面要写上use_frameworks
建pch文件,在pch文件中导入该框架。
#import "ReactiveCocoa.h"
利用这个框架实现下面需求,来具体说明他该如何使用。
两个输入框内都有内容时,下面的按钮是红色。
两个输入框内都没内容时,下面的按钮是灰色。
将下面代码粘贴到项目中的ViewController.m中。
#import "ViewController.h"
#define kMargin 100
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenheight [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property (nonatomic,strong) UITextField *passwordTextFiled;
@property (nonatomic,strong) UITextField *accountTextFiled;
@property (nonatomic,strong) UIButton *OKBtn;
@end
--
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//账号输入框
self.accountTextFiled = [[UITextField alloc]initWithFrame:CGRectMake(kMargin, kMargin, kScreenWidth-kMargin*2, 50)];
self.accountTextFiled.placeholder = @"账号";
self.accountTextFiled.layer.masksToBounds = YES;
self.accountTextFiled.layer.cornerRadius = 5;
self.accountTextFiled.textAlignment = NSTextAlignmentCenter;
self.accountTextFiled.backgroundColor = [UIColor grayColor];
[self.view addSubview:self.accountTextFiled];
//密码输入框
self.passwordTextFiled = [[UITextField alloc]initWithFrame:CGRectMake(kMargin, kMargin*2, kScreenWidth-kMargin*2, 50)];
self.passwordTextFiled.backgroundColor = [UIColor grayColor];
self.passwordTextFiled.placeholder = @"密码";
self.passwordTextFiled.textAlignment = NSTextAlignmentCenter;
self.passwordTextFiled.layer.masksToBounds = YES;
self.passwordTextFiled.layer.cornerRadius = 5;
[self.view addSubview:self.passwordTextFiled];
//确定按钮
self.OKBtn = [UIButton buttonWithType:UIButtonTypeCustom];
self.OKBtn.frame = CGRectMake((kScreenWidth-150)/2, kMargin*3, 150, 50);
self.OKBtn.backgroundColor = [UIColor grayColor];
[self.view addSubview:self.OKBtn];
self.OKBtn.layer.masksToBounds = YES;
self.OKBtn.layer.cornerRadius = 5;
[self.OKBtn setTitle:@"登录" forState:UIControlStateNormal];
}
@end
运行显示如下图:
![](https://img.haomeiwen.com/i1728822/82061eda04657ab2.jpeg)
效果图
不适用RAC来实现上面的需求(不写具体代码了,只写一些过程)
1、遵守协议
2、挂代理
3、实现相应的代理方法
4、在方法内写业务逻辑
使用RAC来实现该业务逻辑
![](https://img.haomeiwen.com/i1728822/767a1838bc146349.jpeg)
1.将上面方法写入ViewController.m中。上面的RAC()其实就是一个宏定义
2.之前咱们说过RAC能帮助我们大量的减少代码而且逻辑更加清晰,在这里我们不需要在.m中找遵守协议的地方,不需要找控件挂代理,不需要去实现方法。
RAC的深入学习
1、 使用RAC给按钮添加事件
//老办法,还要实现clickBtn方法
[self.OKBtn addTarget:self action:@selector(clickBtn) forControlEvents:UIControlEventTouchUpInside];
//rac方法
[[self.OKBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
NSLog(@"OK按钮被点击");
}];
通过rac_signalForControlEvents给按钮创建一个信号流,然后给这个信号指定一个subscribeNext(订阅者)。如果这个信号流的状态发生改变,订阅者便会受到他的改变。不仅仅button可以,segmentcontrol也同样可以。这样操作。
订阅者受到信息以后的操作都在block中操作。block返回来的参数(id x)其实就是用户所点击的按钮。程序员可以直接将(id x)改为(UIButton *sender)。
在找subcribeNext时,会看到这么一个方法
subscribeNext:nil error:nil completed:nil];
第一个参数咱已经说过了,另外事件处理有问题会回调这个error这个block块,点击事件执行完毕以后会调用completed这个block块。
2、使用RAC监听TextFiled的输入变化
[self.accountTextFiled.rac_textSignal subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
self.accountTextFiled.rac_textSignal获得到textfiled的信号流。然后给这个信号指定一个(subscribeNext)订阅者。
subscribeNext:^(id x)如果输入框发生变化,订阅者会收到信息,subscribeNext后的参数,便是输入框的内容。
3、RAC的过滤效果
[[self.passwordTextfiled.rac_textSignal filter:^BOOL(id value) {
NSString *text = value;
BOOL k = [text isEqualToString:@"123"];
return k;
}] subscribeNext:^(id x) {
NSLog(@"======");
}];
这段代码最终实现的效果是,只有密码输入框输入的值是123的时候,subscribe中的代码才能执行。
之前我们已经接触过.rac_textSignal(信号流)和subscirbeNext(订阅者)。上面他们之间的filter的block块便是一个过滤器。在subscriber(订阅者)接受到文本信号变化之前,filter(过滤器)会首先拦截到这个信号。在这个filter进行一个判断,如果filter内返回一个yes,subscribe才会收到文本变化的信号流,返回NO,订阅者就不会收到信息。就好比一个母亲在给自己待嫁的女儿找婆家,只有这名母亲相中了,她才会让女儿去相亲。
4、改变订阅者收到的信息。
[[self.passwordTextFiled.rac_textSignal map:^id(NSString *str) {
return[str boolValue] ? [UIColor clearColor]:[UIColor yellowColor];
}] subscribeNext:^(UIColor *x) {
self.view.backgroundColor = x;
}];
实现的功能:输入框有变化时改变self.view的背景颜色
之前我们subscribe收到的都是输入框的文本内容,现在我们要做的就是改变订阅者收到的信息。
在3中我们提到一个filter(过滤器),在这里我们要用一个map(映射)来改变订阅者收到的信息。之前咱们说filter的时候,在订阅者收到信息之前filter会进行一个拦截。map(映射)其实也拦截一下,拦截的时候同样会收到文本框的变化。他两唯一的不同是在map(映射)中返回的是订阅者收到的东西。上面的母亲给女儿找到了一个对象,已经结婚了。老公的第一个月工资发了,老婆(map)拿着。她那里给老公(subscribe)给你买什么东西,老公用什么东西。
5、对4优化
//对上面的优化
RAC(self.view, backgroundColor) = [self.passwordTextFiled.rac_textSignal map:^id(NSString *passwordValid){
return[passwordValid boolValue] ? [UIColor clearColor]:[UIColor yellowColor];
}];
刚开始咱们使用RAC实现咱们刚开始说的需求时,大家已经见到了RAC()。现在我们做的就是讲map(映射)中返回的颜色。赋值给RAC()中对象控件的对应属性。
总结
起初咱们说到RAC框架有以下几个特点:
1、能够使业务逻辑更清晰
2、减少代码量
3、大量使用block
最后必须要记住的一点是它能做到这一步最为重要的一个原因是
将代理、KVO、通知、callBack等一系列事件,做了一个统一管理。
网友评论