ReactiveCocoa是Github团队开发的第三方函数式响应式编程框架.
官网文档地址:https://github.com/peilinghui/ReactiveCocoa
学习一些优秀的博客地址:
入门教程一
入门教程二
ReactiveCocoa简介
ReactiveCocoa(简称为RAC),是由Github开源的一个应用于iOS和OS开发的新框架.
ReactiveCocoa结合了几种编程风格:
函数式编程(Functional Programming):使用高阶函数,例如函数用其他函数作为参数。
响应式编程(Reactive Programming):关注于数据流和变化传播。
ReactiveCocoa就被开发者们描述为响应式函数编程框架(FRP);使用RAC就不需要考虑调用的顺序,直接考虑结果,使得代码高聚合,方便管理.
一个优点提供了一个单一的、统一的方法去处理异步的行为,包括delegate方法,blocks回调,target-action机制,notifications和KVO.
ReactiveCocoa使用
RACSiganl(RAC的核心类):信号类 用来数据传递
注:
- 该信号默认是一个冷信号,当值改变了,也并不会触发改信号,只有订阅了该信号,才会触发改信号.
- 订阅信号的方法: subscribeNext:
1 | //1.创建一个信号 |
RACSubject:信号提供者,自己可以充当信号,又能发送信号。
使用场景:通常用来代替代理,有了它,就不必要定义代理了。
RACReplaySubject:重复提供信号类,RACSubject的子类。
RACReplaySubject与RACSubject区别:
- RACReplaySubject可以先发送信号,在订阅信号,RACSubject就不可以。
- 使用场景一:如果一个信号每被订阅一次,就需要把之前的值重复发送一遍,使用重复提供信号类。
- 使用场景二:可以设置capacity数量来限制缓存的value的数量,即只缓充最新的几个值。
RACSubject和RACReplaySubject简单使用:
RACSubject使用步骤
1.创建信号 [RACSubject subject],跟RACSiganl不一样,创建信号时没有block。
2.订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
3.发送信号 sendNext:(id)value
**RACSubject:底层实现和RACSignal不一样**
1.调用subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值了。
2.调用sendNext发送信号,遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock。
1 | // 1.创建信号 |
RACReplaySubject使用步骤:
1.创建信号 [RACSubject subject],跟RACSignal不一样,创建信号时没有block。
2.可以先订阅信号,也可以先发送信号。
2.1 订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
2.2 发送信号 sendNext:(id)value
// RACReplaySubject:底层实现和RACSubject不一样。
// 1.调用sendNext发送信号,把值保存起来,然后遍历刚刚保存的所有订阅者,一个一个调用订阅者的nextBlock。
// 2.调用subscribeNext订阅信号,遍历保存的所有值,一个一个调用订阅者的nextBlock
// 如果想当一个信号被订阅,就重复播放之前所有值,需要先发送信号,在订阅信号。
// 也就是先保存值,在订阅值。
// 1.创建信号
RACReplaySubject *replaySubject = [RACReplaySubject subject];
// 2.发送信号
[replaySubject sendNext:@1];
[replaySubject sendNext:@2];
// 3.订阅信号
[replaySubject subscribeNext:^(id x) {
NSLog(@"第一个订阅者接收到的数据%@",x);
}];
// 订阅信号
[replaySubject subscribeNext:^(id x) {
NSLog(@"第二个订阅者接收到的数据%@",x);
}];
RACSubject替换代理
// 需求:
// 1.给当前控制器添加一个按钮,modal到另一个控制器界面
// 2.另一个控制器view中有个按钮,点击按钮,通知当前控制器
步骤一:在第二个控制器.h,添加一个RACSubject代替代理。
@interface TwoViewController : UIViewController
@property (nonatomic, strong) RACSubject *delegateSignal;
@end
步骤二:监听第二个控制器按钮点击
1 | @implementation TwoViewController |
步骤三:在第一个控制器中,监听跳转按钮,给第二个控制器的代理信号赋值,并且监听.
1 | @implementation OneViewController |
替换Target和Action
TextField的字符变化
[[self.textFild.rac_textSignal map:^id(id value) {
NSLog(@"%@", value);
return @1;
}] subscribeNext:^(id x) {
NSLog(@"%@", x);
}];
map构造的映射块value的值就是控件中的字符变化,根据这个功能我们就可以对我们监测的东西和我们需求的东西进行转换。比如监听了字符串变化,我们需要的时变化后的字符串长度而不是变化的字符串本身,则可以在map的返回值中返回text.length,就可以实时捕获到字符串长度;甚至做一个映射表,将各个变化进行一对一或者一对多或者多对一的处理。
filter就是过滤,它可以帮助你筛选出你需要的信号变化。
take是获取,skip是跳过,这两个方法后面跟着的都是NSInteger。所以take 2就是获取前两个信号,skip 2就是跳过前两个。repeat是重复发送信号。
delay延时信号,顾名思义,即延迟发送信号.
throttle搜索框的时候,有时候需求的时实时搜索,即用户每每输入字符,view都要求展现搜索结果。这时如果用户搜索的字符串较长,那么由于网络请求的延时可能造成UI显示错误,并且多次不必要的请求还会加大服务器的压力,这显然是不合理的,此时我们就需要用到节流。
distinctUntilChanged网络请求中为了减轻服务器压力,无用的请求我们应该尽可能不发送。distinctUntilChanged的作用是使RAC不会连续发送两次相同的信号,这样就解决了这个问题。
timeout超时信号,当超出限定时间后会给订阅者发送error信号。
ignore忽略信号,指定一个任意类型的量(可以是字符串,数组等),当需要发送信号时讲进行判断,若相同则该信号会被忽略发送。
UIButton的事件的监听
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
//这个x就是button,已经知道了类型就可以把id x 修改成UIButton *button
NSLog(@”%@”,x);
}];
手势事件
UITapGestureRecognizer *tap =[[UITapGestureRecognizer alloc]init];
[[tap rac_gestureSignal] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
[self.view addGestureRecognizer:tap];
通知
RAC的通知不需要移除remove observer,因为在rac_add方法中他已经写了remove
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(id x) {
NSLog(@”%@”,x);
}];
定时器
//延迟一定时间做某事
[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
NSLog(@”Ricky”);
}];
//每个多长时间调用一次事件
[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id x) {
NSLog(@”%@”,x);
}];
KVO
RACObserve(TARGET, KEYPATH)这种形式,TARGET是监听目标,KEYPATH是要观察的属性值
监听UIScrollView的contentOffset
UIScrollView *scroller =[[UIScrollView alloc]initWithFrame:CGRectMake(100, 100, 100, 200)];
[self.view addSubview:scroller];
[RACObserve(scroller, contentOffset) subscribeNext:^(id x) {
NSLog(@”%@”,x);
}];