RAC
指的就是 RactiveCocoa
,是 Github
的一个开源框架,能够帮我们提供大量方便的事件处理方案,让我们更简单粗暴地去处理事件,现在分为 ReactiveObjC
和 ReactiveSwift
,两个框架的功能使用相似,由于正好在学习这个然后公司项目是用 OC
写的,所以将 ReactiveObjC
的使用方法记录一下。
ReactiveObjC 的使用
RAC
的核心思想:创建信号
- 订阅信号
- 发送信号
,并且在 RAC
中我们会看到大量的 block
,所以在使用之前可以再重新温习一下 block
的使用。
1. RACSignal 信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) { [subscriber sendNext:@"发送信号"]; return nil; }];
RACDisposable *disposable = [signal subscribeNext:^(id _Nullable x) { NSLog(@"信号内容:%@", x); }];
[disposable dispose];
|
2. RACSubject 信号
和代理的用法类似,通常用来代替代理,有了它,就不必要定义代理了。
RACSubject *subject = [RACSubject subject];
[subject sendNext:@"发送信号"];
[subject subscribeNext:^(id _Nullable x) { NSLog(@"信号内容:%@", x); }];
|
3. RACTuple 元祖
RAC
的元祖,跟我们 OC
的数组其实是一样的,它其实就是封装了我们 OC
的数组。
RACTuple *tuple = [RACTuple tupleWithObjects:@"1", @"2", @"3", @"4", @"5", nil];
RACTuple *tuple = [RACTuple tupleWithObjectsFromArray:@[@"1", @"2", @"3", @"4", @"5"]];
RACTuple *tuple = RACTuplePack(@"1", @"2", @"3", @"4", @"5");
NSLog(@"取元祖内容:%@", tuple[0]); NSLog(@"第一个元素:%@", [tuple first]); NSLog(@"最后一个元素:%@", [tuple last]);
|
4. 便利 Array 数组和 Dictionary 字典
可以省去使用 for
循环来遍历。
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"]; [array.rac_sequence.signal subscribeNext:^(id _Nullable x) { NSLog(@"数组内容:%@", x); }];
|
NSDictionary *dictionary = @{@"key1":@"value1", @"key2":@"value2", @"key3":@"value3"}; [dictionary.rac_sequence.signal subscribeNext:^(RACTuple * _Nullable x) { RACTupleUnpack(NSString *key, NSString *value) = x; NSLog(@"字典内容:%@:%@", key, value); }];
|
下面两个方法都是将数组内容全部换为 0
,第一个是单个操作,,第二个是一次性全部替换,两个方法都不会改变原数组内容,操作完后都会生成一个新的数组,省去了创建可变数组然后遍历出来单个添加的步骤。
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"]; NSArray *newArray = [[array.rac_sequence map:^id _Nullable(id _Nullable value) { NSLog(@"数组内容:%@", value); return @"0"; }] array];
|
NSArray *array = @[@"1", @"2", @"3", @"4", @"5"]; NSArray *newArray = [[array.rac_sequence mapReplace:@"0"] array];
|
5. 监听 TextField 的输入改变
可以省去设置 delegate
和实现代理方法的步骤。
[[textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) { NSLog(@"输入框内容:%@", x); }];
|
[[textField.rac_textSignal filter:^BOOL(NSString * _Nullable value) { return value.length > 5; }] subscribeNext:^(NSString * _Nullable x) { NSLog(@"输入框内容:%@", x); }];
|
可以省去 addTarget
添加事件和创建方法的步骤。
[[button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) { NSLog(@"%@ 按钮被点击了", x); }];
|
7. 登录按钮状态实时监听
下面表示只有 用户名
和 密码
输入框内容都大于 0
时,登录
按钮才可以点击,而且状态是实时监听的,一句代码就能完成这个功能。
RAC(_loginButton, enabled) = [RACSignal combineLatest:@[_username.rac_textSignal, _password.rac_textSignal] reduce:^id _Nullable(NSString * username, NSString * password){ return @(username.length && password.length); }];
|
8. 监听 Notification 通知事件
可省去在 -(void)dealloc {}
中清除通知和监听通知创建方法的步骤。
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardDidShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) { NSLog(@"%@ 键盘弹起", x); }];
|
9. 代替 Delegate 代理方法
可以省去监听以及设置 delegate
的步骤,下面表示只要 view
中执行了 btnClick
这个方法,就会发送信号执行这个回调。
[[view rac_signalForSelector:@selector(btnClick)] subscribeNext:^(RACTuple * _Nullable x) { NSLog(@" view 中的按钮被点击了"); }];
|
10. 代替 KVO 监听
可以代替 KVO
监听,下面表示把监听 view
的 frame
属性改变转换成信号,只要值改变就会发送信号。
[[view rac_valuesForKeyPath:@"frame" observer:self] subscribeNext:^(id _Nullable x) { NSLog(@"属性的改变:%@", x); }];
|
还有一种更简单的写法,就是利用 RAC
的宏,和上面的效果是一样的。
[RACObserve(view, frame) subscribeNext:^(id _Nullable x) { NSLog(@"属性的改变:%@", x); }];
|
11. 代替 NSTimer 计时器
可以代替 NSTimer
使用。
@interface ViewController ()
@property (nonatomic, strong) RACDisposable *disposable;
@end
|
self.disposable = [[RACSignal interval:1.0 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSDate * _Nullable x) { NSLog(@"当前时间:%@", x); [_disposable dispose]; }];
|