RAC 指的就是 RactiveCocoa ,是 Github 的一个开源框架,能够帮我们提供大量方便的事件处理方案,让我们更简单粗暴地去处理事件,现在分为 ReactiveObjC 和 ReactiveSwift ,两个框架的功能使用相似。本人主要是用OC开发,swift开发的不多。
我们通常用到的响应式编程方法有哪些?显然最常用的有代理、通知、KVO等等!RAC就是简化封装后响应式编程!
利用cocoapod导入:
纯OC开发的伙伴导入ReactiveObjC框架:
pod 'ReactiveObjC', '~> 2.1.0'
或者导入ReactiveCocoa框架:
pod 'ReactiveCocoa', '~> 2.5.0'
注意:纯OC开发的伙伴在导入ReactiveCocoa的时候,不要导入5.0的版本,因为在5.0版本的时候里面加入了swift,导入会报错的!!!不会cocoapod 到这里看看
一、ReactiveObjC 的信号使用
RAC 的核心思想:创建信号 - 订阅信号 - 发送信号 ,并且在 RAC 中我们会看到大量的 block 。
1.关于RACSignal 信号
// 创建信号
RACSignal *single = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"汉堡"];
return nil;
}];
// 订阅信号
RACDisposable *dispos = [single subscribeNext:^(id _Nullable x) {
NSLog(@"我晚上吃:%@",x);
}];
// 取消订阅
[dispos dispose];
2.RACSubject 信号
继承自RACSignal,和代理的用法类似,通常用来代替代理,有了它,就不必要定义代理了。
// 创建信号
// 其实内部实现就是创建一个数组,还创建了一个RACDisposable,所以下面订阅的时候不需要你在返回一个RACDisposable了
RACSubject *subject = [RACSubject subject];
// 订阅信号(通常在别的视图控制器中订阅,与代理的用法类似);
// 这个地方是函数式编程思想
// 创建订阅者,将block保存到订阅者对象,将订阅者保存到数组中
[subject subscribeNext:^(id _Nullable x) {
// 回调
NSLog(@"我晚上吃:%@",x);
}];
// 发送信号
[subject sendNext:@"汉堡"];
3. 代替 Delegate 代理方法
可以省去监听以及设置Delegate的步骤,下面表示只要self.subView中执行了 buttonClick1 这个方法,就会发送信号执行这个回调。
[[self.subView rac_signalForSelector:@selector(buttonClick1)] subscribeNext:^(id _Nullable x) {
NSLog(@"不要代理,有我就够了呀!");
}];
4. 监听 Button 点击事件
[[self.loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"我被点击了");
}];
// 实现当输入框有内容的时候button才能点击,用下面方法就可实现
// RAC() 这个宏可以研究下,有好多用法!!!
RAC(_loginBtn, enabled) = [RACSignal combineLatest:@[_textField.rac_textSignal] reduce:^id _Nullable(NSString *username){
return @(username.length);
}];
5. 监听一个方法是否被调用了
我们在self.subView的.里面写一个私有方法 look: ,然后通过点击按钮调用这个方法,我们在控制器里监听这个方法。
// 我们来看能不能监听到这个方法调用
[[self.subView rac_signalForSelector:@selector(look:)] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
6. 代替 KVO 监听
可以代替 KVO 监听,下面表示把监听 self.subView 的 frame 属性改变转换成信号,只要值改变就会发送信号。看下原来的KVO怎么用的。
[[self.subView rac_valuesForKeyPath:@"frame" observer:self] subscribeNext:^(id _Nullable x) {
NSLog(@"哎呀,subView的frame变了:%@",x);
}];
7. 监听 Notification 通知事件
可省去在 -(void)dealloc {} 中清除通知和监听通知创建方法的步骤。
// 这里我们监听下键盘的弹出
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"哎呀,键盘弹出来了");
}];
8. 监听 TextField 的输入改变
监听textField的内容输入,当内容改变就会调用
[[self.textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"输入框内容:%@", x);
}];
9. 代替 NSTimer 计时器
[[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) {
NSLog(@"当前时间:%@",x);
}];
注意:RAC的定时器,其实是封装GCD的定时器。
一、ReactiveObjC数组的使用
1.RACTuple
// 创建元组
RACTuple *tuple1 = [RACTuple tupleWithObjects:@"a",@"b",@"c", nil];
// 从别的数组中获取内容
RACTuple *tuple2 = [RACTuple tupleWithObjectsFromArray:@[@"a",@"b",@"c"]];
// 利用RAC宏快速封装
RACTuple *tuple3 = RACTuplePack(@"a",@"b",@"c");
NSLog(@" tuple1:%@ \n tuple2:%@ \n tuple3:%@",tuple1,tuple2,tuple3);
NSLog(@"%@ %@ %@",tuple1[0],tuple2[0],tuple3[0]);
2.便利 Array 数组和 Dictionary 字典
// 1.遍历数组
RACTuple *tuple = [RACTuple tupleWithObjects:@"a",@"b",@"c", nil];
[tuple.rac_sequence.signal subscribeNext:^(id _Nullable x) {
NSLog(@"tuple:%@",x);
}];
// 这个是不是有点像OC数组的block遍历方式,我们来对比一下
NSArray *array = @[@"a",@"b",@"c"];
[array enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSLog(@"array:%@",obj);
}];
// 2.遍历字典
NSDictionary *dictionary = @{@"1":@"a",@"2":@"b",@"3":@"c",};
[dictionary.rac_sequence.signal subscribeNext:^(RACTuple * _Nullable x) {
// Unpack:拆分,我么可以看到每个键值对都被拆都被拆分为了一个数组,这个x是个元组类型,这个宏能够将key和value拆分开
// 大家若是不理解,可以点RACTupleUnpack进去看看它们的例子就明台,只是一种语法而已
RACTupleUnpack(NSString *key, NSString *value) = x;
NSLog(@"键值对:%@:%@", key, value);
}];
3.数组内元素替换
// 下面两个方法都是将数组内容全部换为 0 ,第一个是单个操作,,第二个是一次性全部替换,两个方法都不会改变原数组内容,操作完后都会生成一个新的数组,省去了创建可变数组然后遍历出来单个添加的步骤。
NSArray *newArray1 = [[array.rac_sequence map:^id _Nullable(id _Nullable value) {
NSLog(@"数组内容:%@", value);
return @"0"; // 将所有内容替换为 0
}] array];
NSLog(@"新数组:%@ 老数组:%@",newArray1,array);
// 内容快速替换
NSArray *newArray2 = [[array.rac_sequence mapReplace:@"0"] array]; // 将所有内容替换为 0
NSLog(@"新数组:%@",newArray2);
4.筛选数组中你想要的元素
NSArray *newArray3 = [[array.rac_sequence filter:^BOOL(id _Nullable value) {
if ([value isEqualToString:@"a"] || [value isEqualToString:@"b"]) {
return YES;
}else{
return NO;
}
}] array];
5.删除数组中的某个元素
NSArray *newArray4 = [[array.rac_sequence ignore:@"a"] array];
这里只是对RAC简要的功能介绍,更多的有趣功能需要你在开发中去探索研究,很不错的框架,非常值得学习。Demo下载地址。