一、ReactiveCocoa简介
- ReactiveCocoa是苹果iOS开发的开源库。其实里面十分灵活的运用Block,其最大的营养就是他的编程思想。
二、好用编程思想
-
写过swift的就会发现,它调用方法的方式大都是通过
.
的方式,传参是通过.方法名(参数)
的方式。说明苹果也在推荐使用的吧。 -
优点
:用OC的方式可能要写几行代码才能达到想要的效果。而链式编程+函数式编程,就是一行代码就能搞定,而且通熟易懂。代码高聚合,方便管理。 -
链式编程思想
:就是方法函数通过.
的方式来调用 -
函数式编程思想
:.方法名(函数(返回自身对象))
-
响应式编程思想
:不需要考虑调用顺序,只需要知道考虑结果,类似于蝴蝶效应,产生一个事件,会影响很多东西,这些事件像流一样的传播出去,然后影响结果,借用面向对象的一句话,万物皆是流。 -
链式编程+函数式编程的代表作
:masnory
// 第三方库masnory简单使用
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.mas_equalTo(0);
make.centerY.mas_equalTo(-150);
make.width.mas_equalTo(88);
make.height.mas_equalTo(50);
}];
2.1 实学实用
- 很简单的
- 来一波大白话解释:
manager.add(2,2).sub(1).muilt(2).divide(3);
1. 在OC中,block可以用`方法名()`的方式来调用,调用Block的时候,blockName(params)。所以add(param)和sub(param)这两个方法,肯定返回值是一个Block,而且是带一个参数的Block。
2. 通过 `.` 调用方法其实就是调用getter方法,所以add和sub方法没有参数,只有一个返回类型为Block的值。
3. 为什么能一直点下去,因为Block也有返回值,而且返回值的类型就是当前对象的类型。
- 通过实际案例开发的方式,能更快速的理解链式编程和函数式编程。接下来通过实例来加推理解。
2.2 使用链式编程+函数编程来写一个计算器功能
- 创建计算器管理者CalculateManager,并声明实例方法和加减乘除方法。
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class WMCalculateManager;
typedef WMCalculateManager *(^CalculateName)(CGFloat value);// 声明一个公开类型:带CGFloat类型的参数,返回WMCalculateManager类型,名字为CalculateName的block类型
@interface WMCalculateManager : NSObject
@property (nonatomic, copy) CalculateName calculateName;
// 参数(函数):带有本类对象的、无返回值类型 函数(block)
+ (CGFloat)makeCalculateManagerWith:(void(^)(WMCalculateManager *manager))managerBlock;
- (WMCalculateManager *(^)(CGFloat value1,CGFloat value2))add;
- (CalculateName)sub;
- (CalculateName)muilt;
- (CalculateName)divide;
@end
- 执行上面声明的方法:
@interface WMCalculateManager ()
@property (nonatomic, assign) CGFloat result;
@end
@implementation WMCalculateManager
+ (CGFloat)makeCalculateManagerWith:(void (^)(WMCalculateManager *))managerBlock {
// 创建自身实例化
WMCalculateManager *manager = [[WMCalculateManager alloc] init];
// 调用managerBlock,把 自身实例化对象 当参数
managerBlock(manager);
// 返回值
return manager.result;;
}
- (WMCalculateManager *(^)(CGFloat value1, CGFloat value2))add {
// 返回值 是 一个 带 自身返回值 和 参数 的函数
return ^WMCalculateManager *(CGFloat value1, CGFloat value2){
_result = value1 + value2 ;
return self;
};
}
- (CalculateName)sub {
return ^WMCalculateManager *(CGFloat value1) {
_result -= value1;
return self;
};
}
- (CalculateName)muilt {
return ^WMCalculateManager *(CGFloat value1) {
_result = _result * value1;
return self;
};
}
- (CalculateName)divide {
return ^WMCalculateManager *(CGFloat valuea) {
_result = _result / valuea;
return self;
};
}
@end
- 使用上面创建的计算器
CGFloat result = [WMCalculateManager makeCalculateManagerWith:^(WMCalculateManager *manager) {
manager.add(2,2).sub(1).muilt(2).divide(3);
}];
_resultLab.text = [NSString stringWithFormat:@"结果:%.1f",result];
NSLog(@"result:%.1f",result);
// 输出结果:result:2.000000
- 接下来就参照以上的模式应用到自己的项目中吧。可以用到很多地方。你会发现越来越喜欢使用Block回调的方式+链式。
三、ReactiveCocoa编程思想
- 翻篇了
- 那是不可能滴,这辈子是不可能滴。以上的编程思想理解之后,再往下看ReactiveCocoa辣是so easy,辣里不会点辣里。又犯二=_=!!
- 开发中不可避免的使用牛人们开发好的框架,好用省时间,但不要太过依赖,否则人家不更新了就导致项目后期不好维护。对一个框架的学习,主要学习其编程思想。四面八方通罗马,达到同一个目的有很多种思路,看你走哪条路,别人怎么走的sa。
四、ReactiveCocoa使用
4.1. ReactiveCocoa导入
- ReactiveCocoa5.0以后将RAC拆分为四个库:ReactiveCocoa、ReactiveSwift、ReactiveObjC、ReactiveObjCBridge。其中的ReactiveCocoa和ReactiveObjC,一个适用于您的纯Swift项目,另一个适用于纯OC项目。
- 有多种方式导入。我是使用Cocoapods导入。我项目是纯OC,故导入ReactiveObjC
pod 'ReactiveObjC'
4.2 ReactiveCocoa常用的应用场景
-
总结6个常用的应用场景:
4.2.1 替代代理 -
rac_signalForSelector
:用于替代代理
4.2.2 替代KVO -
rac_valuesAndChangesForKeyPath
:用于监听某个对象的属性改变。
4.2.3 替代通知 -
rac_addObserverForName
:用于监听某个通知。
4.2.4 监听事件 -
rac_signalForControlEvents
:用于监听某个事件。
4.2.5 监听文本框 -
rac_textSignal
:只要文本框发出改变就会发出这个信号。
4.2.6 处理当界面有多次请求时,需要都获取到数据时,才能展示界面(这个非常好用) -
rac_liftSelector:withSignalsFromArray:Signals
:当传入的Signals(信号数组),每一个signal都至少sendNext过一次,就会去触发第一个selector参数的方法。 - 使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。
-
老规矩,用实例说话,推进理解↓
// 1.代替代理
// 需求:自定义redView,监听红色view中按钮点击
// 之前都是需要通过代理监听,给红色View添加一个代理属性,点击按钮的时候,通知代理做事情
// rac_signalForSelector:把调用某个对象的方法的信息转换成信号,就要调用这个方法,就会发送信号。
// 这里表示只要redV调用btnClick:,就会发出信号,订阅就好了。
[[redV rac_signalForSelector:@selector(btnClick:)] subscribeNext:^(id x) {
NSLog(@"点击红色按钮");
}];
// 2.KVO
// 把监听redV的center属性改变转换成信号,只要值改变就会发送信号
// observer:可以传入nil
[[redV rac_valuesAndChangesForKeyPath:@"center" options:NSKeyValueObservingOptionNew observer:nil] subscribeNext:^(id x) {
NSLog(@"%@",x);
}];
// 3.监听事件
// 把按钮点击事件转换为信号,点击按钮,就会发送信号
[ __weak typeof(self) weakSelf = self;// 注意:block中self要弱引用,避免强强引用无法释放。
[[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
// 点击按钮就会来到这里发送信号
[weakSelf caculateName1:btn];
}];
// 4.代替通知
// 把监听到的通知转换信号
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(id x) {
NSLog(@"键盘弹出");
}];
// 5.监听文本框的文字改变
[_textField.rac_textSignal subscribeNext:^(id x) {
NSLog(@"文字改变了%@",x);
}];
// 6.处理多个请求,都返回结果的时候,统一做处理.
RACSignal *request1 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求1
[subscriber sendNext:@"发送请求1"];
return nil;
}];
RACSignal *request2 = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// 发送请求2
[subscriber sendNext:@"发送请求2"];
return nil;
}];
// 使用注意:几个信号,参数一的方法就几个参数,每个参数对应信号发出的数据。
[self rac_liftSelector:@selector(updateUIWithR1:r2:) withSignalsFromArray:@[request1,request2]];
}
// 更新UI
- (void)updateUIWithR1:(id)data r2:(id)data1
{
NSLog(@"更新UI%@ %@",data,data1);
}
4.3. ReactiveCocoa常用方法
RACSignal 信号类
- RACSignal信号类,当有数据改变,信号内部收到数据就会交给内部一个订阅者去发信号传递数据。
- 默认一个信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发
// RACSignal使用步骤:
// 1.创建信号 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
// 2.订阅信号,才会激活信号. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.发送信号 - (void)sendNext:(id)value
// RACSignal底层实现:
// 1.创建信号,首先把didSubscribe保存到信号中,还不会触发。
// 2.当信号被订阅,也就是调用signal的subscribeNext:nextBlock
// 2.2 subscribeNext内部会创建订阅者subscriber,并且把nextBlock保存到subscriber中。
// 2.1 subscribeNext内部会调用siganl的didSubscribe
// 3.siganl的didSubscribe中调用[subscriber sendNext:@1];
// 3.1 sendNext底层其实就是执行subscriber的nextBlock
// 1.创建信号 先保存信号代码,还不会被触发
_signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// block调用时刻:每当有订阅者信号,就会调用block
// 2. 发送信号
[subscriber sendNext:@1];
// 3.发送完成(如果不再发送数据,最好发送信号完成,内部会自动调用[RACDisposable disposable]取消订阅信号)
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// block调用时刻:当信号发送完成或者发送错误,就会自动执行这个block,取消订阅信号。
// 执行完Block后,当前信号就不在被订阅了。
DLog(@"发送完成或发送错误,总之信号被销毁");
}];
}];
// 3.订阅信号,才会激活信号.
[_signal1 subscribeNext:^(id _Nullable x) {
DLog(@"\n接收到数据:%@\n",x);
}];
RACDisposable
- 用于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会自动触发它。
-
使用场景
:不想监听某个信号时,可以通过它主动取消订阅信号。
RACSubject
- RACSubject:信号提供者,自己可以充当信号,又能发送信号。
4.4. ReactiveCocoa常见的宏
-
RAC(TARGET, [KEYPATH, [NIL_VALUE]])
:用于给某个对象的某个属性绑定。 -
RACObserve(self, name)
:监听某个对象的某个属性,返回的是信号。 -
@weakify(Obj)和@strongify(Obj)
,一般两个都是配套使用,在主头文件(ReactiveCocoa.h)中并没有导入,需要自己手动导入,RACEXTScope.h才可以使用。但是每次导入都非常麻烦,只需要在主头文件自己导入就好了。 -
RACTuplePack
:把数据包装成RACTuple(元组类) -
RACTupleUnpack
:把RACTuple(元组类)解包成对应的数据。
网友评论