RAC 初探
2019-07-08 本文已影响0人
J扣歪
RAC是利用函数式+响应式编程思想封装的一套框架.为低耦合高内聚开发提供了方便.
一 基本用法
- UIButton
[[_button rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"点击事件会触发这里");
}];
- UITextField
[_textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
NSLog(@"实时监听texfield输入框的文字%@",x);
}];
3.KVO
Person *p = Person.new;
[p rac_observeKeyPath:@"name" options:(NSKeyValueObservingOptionNew) observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
NSLog(@"KVO监听事件会触发这里");
}];
p.name = @"lala";
- 通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
NSLog(@"键盘弹起会触发这里%@",x);
}];
- 宏
Person *p = Person.new;
//信号绑定 对象p的name属性会随_textField输入框的值实时变化
RAC(p,name) = _textField.rac_textSignal;
//KVO 属性监听p的name属性
[RACObserve(p, name) subscribeNext:^(id _Nullable x) {
NSLog(@"监听到了%@",x);
}];
二 信号
- subject
//创建信号
RACSubject *subject = [RACSubject subject];
//订阅信号
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
//发送消息
[subject sendNext:@"hello"];
- RACSignal
//创建
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//发送
[subscriber sendNext:@"模拟数据请求!"];
});
return [RACDisposable disposableWithBlock:^{
NSLog(@"信号销毁");
}];
}];
//订阅
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
- map
RACSubject *subject = [RACSubject subject];
[[subject map:^id _Nullable(id _Nullable value) {
NSLog(@"1==%@",value);
return [NSString stringWithFormat:@"%@ RAC!",value];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"2====%@",x);
}];
[subject sendNext:@"hello"];
控制台输出:
1==hello
2====hello RAC!
- flattenMap
RACSubject *subject = [RACSubject subject];
[[[subject flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
RACSignal *sign = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:@"只有当我发送消息才会执行下一步"];
});
return nil;
}];
[sign subscribeNext:^(id _Nullable x) {
NSLog(@"1.%@",x);
}];
return sign;
}] flattenMap:^__kindof RACSignal * _Nullable(id _Nullable value) {
NSLog(@"2.%@",value);
return [RACReturnSignal return:[NSString stringWithFormat:@"%@ 执行完毕!",value]];
}] subscribeNext:^(id _Nullable x) {
NSLog(@"3.%@",x);
}];
[subject sendNext:@"执行"];
控制台输出:
1.只有当我发送消息才会执行下一步
2.只有当我发送消息才会执行下一步
3.只有当我发送消息才会执行下一步 执行完毕!
- 同时处理多个信号
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"模拟数据请求1"];
return nil;
}];
RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"模拟数据请求2"];
return nil;
}];
[self rac_liftSelector:@selector(recive:td:) withSignals:signal1,signal2, nil];
- (void)recive:(id)data1 td:(id)data2{
//只有当两个信号都发送了才会执行此方法
NSLog(@"%@,%@",data1,data2);
}
控制台输出: 模拟数据请求1,模拟数据请求2
和上面类似
RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"模拟数据请求1"];
return nil;
}];
RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"模拟数据请求2"];
return nil;
}];
[[RACSignal combineLatest:@[signal1,signal2] reduce:^(NSString *d1,NSString *d2){
NSLog(@"1.%@%@",d1,d2);
return @"hello";
}] subscribeNext:^(id _Nullable x) {
NSLog(@"2.%@",x);
}];
控制台输出 :
1.模拟数据请求1模拟数据请求2
2.hello
- RACCommand
RACCommand *command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
NSLog(@"1.%@",input);
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"发送"];
return nil;
}];
}];
[command.executing subscribeNext:^(NSNumber * _Nullable x) {
if ([x integerValue] == 0) {
NSLog(@"正在执行");
}else{
NSLog(@"执行完毕");
}
}];
RACSignal *commandSignal = [command execute:@"执行"];
[commandSignal subscribeNext:^(id _Nullable x) {
NSLog(@"2.%@",x);
}];
输出:
正在执行
1.执行
执行完毕
2.发送
UIButton *btn = _button;
btn.rac_command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
//点击按钮回调这里
NSLog(@"我是button:%@",input);
return [RACSignal empty];
}];
三 RAC+MVVM 案例
1.模拟登录请求
//RAC绑定登录按钮是否可点击属性信号
RAC(_loginButton,enabled) = [RACSignal combineLatest:@[_phoneField.rac_textSignal,
_passwordField.rac_textSignal]
reduce:^(NSString *phoneText,NSString *passwordText){
//只有当手机号和密码长度都大于0时返回yes
return @(phoneText.length>0&&passwordText.length>0);
}];
//登录按钮点击事件
@weakify(self);
[[_loginButton rac_signalForControlEvents:(UIControlEventTouchUpInside)] subscribeNext:^(__kindof UIButton * loginBtn) {
@strongify(self);
[loginBtn setTitle:@"登录中..." forState:(UIControlStateNormal)];
//返回订阅信号
RACSignal *signal = [LoginViewModel loginWith:self.phoneField.text password:self.passwordField.text];
//订阅信号 等待登录请求返回
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"登陆成功");
[loginBtn setTitle:@"登录" forState:(UIControlStateNormal)];
}];
[signal subscribeError:^(NSError * _Nullable error) {
NSLog(@"登陆失败");
[loginBtn setTitle:@"登录" forState:(UIControlStateNormal)];
}];
}];
LoginViewModel 代码
+ (RACSignal *)loginWith:(NSString *)phonestr password:(NSString *)pwdstr{
//创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//模拟登录请求耗时
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//发送消息
[subscriber sendNext:@"登录成功!"];
});
return nil;
}];
return signal;
}
2. 模拟数据加载
调用代码
//viewModel
_viewModel = DataViewModel.new;
//数据条数 用于模拟数据
_data = 10;
@weakify(self);
//下拉刷新控件及事件
_mainTableView.qy_header = [QYRefreshNormalHeader headerWithRefreshingBlock:^{
@strongify(self);
//发起下拉刷新数据请求 10条数据
[self.viewModel.command execute:@(10)];
}];
//上拉加载控件及事件
_mainTableView.qy_footer = [QYRefreshNormalFooter footerWithRefreshingBlock:^{
@strongify(self);
//发起上拉加载数据请求 +10
[self.viewModel.command execute:@(self.data+10)];
}];
//订阅信号 等待数据返回 再刷新TableView
[self.viewModel.command.executionSignals.switchToLatest subscribeNext:^(id _Nullable x) {
@strongify(self);
self.data = [x integerValue];
[self.mainTableView reloadData];
[self.mainTableView.qy_footer endRefreshing];
[self.mainTableView.qy_header endRefreshing];
}];
DataViewModel 代码
- (RACCommand *)command{
if (!_command) {
_command = [[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable input) {
//返回信号
return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//模拟网络耗时请求
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[subscriber sendNext:input];
[subscriber sendCompleted];//不加此句代码指令执行一次后将会被禁用
});
return nil;
}];
}];
}
return _command;
}