XZ_iOS之RAC(ReactiveCocoa)的介绍和使用
来源:互联网 发布:淘宝买家秀招聘 编辑:程序博客网 时间:2024/05/23 20:14
RAC1-介绍
简介
GitHub团队开发的一套开源框架;超重量级的框架;接管了苹果中的所有消息机制;
全称ReactiveCocoa,响应式编程(FRP)在iOS中的一个实现框架,现在OC版本的只到3.0.0版本就不再更新了,swift版本有持续更新;
目的:事件监听
用信号接管了苹果中的所有事件机制,包括:
- addTarget:监听,点击按钮之后调用回调方法;
- 代理(delegate):在主控件里发生某个事情的时候,通过协议的方式通知我们去执行协议的方法;双方有个约定好的协议,调用方实现协议方法,接收方在需要的时候通知调用方delegate,执行协议方法。
- 通知:通过注册字符串的方式,当接收到通知之后,监听者去做一些事情;
- KVO:通过监听属性变化来实现监听
- 时钟
- 网络异步回调
block不是事件机制,block是提前好的代码传递给接受方,接收方在拿到block之后,在需要的时候直接执行block,不再跟回来有关系了。从调用方来说,准备好的block,传给接收方,我们是不管接收方什么时候执行的。所以,block不属于事件监听。
特点
学习起来非常难;团队开发时需特别谨慎,需要不断地代码评审,保证团队中所有人的代码风格一致!
RAC的重要概念
信号
RAC的核心思想
所谓响应,就是事件发生后做出响应
框架特点
- 超重量级的核心框架,学习成本较高
- 利用信号,接管iOS的所有事件
- 利用block将所有相关代码集中在一起,从一定程度上解决了代码分散的问题;
- 使用时需要注意循环引用,注册 rac_willDeallocSignal 信号能够跟踪对象是否被释放
- 通过KVO监听,能够及时将模型数据变化体现在界面上
RAC最为核心的概念:1>RAC接管了了所有的事件机制,2>信号刚刚创建的时候,是冷信号,不会工作,只有被订阅者订阅了之后才是热信号,才会执行。3>如何传递信息:在信号内部给订阅者通过send三个方法告诉订阅者他对应的方法,订阅者只需要监听不同的代码块,就可以在不同的代码块获得自己想要的东西了。
网络请求的时候,使用RAC实现监听,订阅者收到相应的方法时,获取自己想要的东西,并作出相应的操作。
Demo地址
https://github.com/CoderXAndZ/RAC
XZPersonListModel.h
//列表数据模型,负责加载数据(包含网络数据/本地缓存数据)
@interface XZPersonListModel :NSObject
//联系人数组,泛型数组
@property (nonatomic)NSMutableArray <XZPerson *> *personList;
//加载联系人数组返回一个RAC的信号
- (RACSignal *)loadPersons;
@end
XZPersonListModel.m
- (RACSignal *)loadPersons {
NSLog(@"==============%s",__FUNCTION__);
//直接返回一个 RAC的信号
//一旦有了订阅者,block内部的代码能够执行
return [RACSignalcreateSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
//发送不同的信号
_personList = [NSMutableArrayarray];
//模拟异步加载数据
dispatch_async(dispatch_get_global_queue(0,0), ^{
//模拟延时
[NSThreadsleepForTimeInterval:1.0];
//创建数据
for (NSInteger i =0; i <20; i++) {
XZPerson *person = [[XZPersonalloc]init];
person.name = [@"zhangsan - "stringByAppendingFormat:@"%ld",(long)i];
person.age = 15 +arc4random_uniform(20);
[_personListaddObject:person];
}
NSLog(@"%@",_personList);
//完成回调发送信号给订阅者,主线程
dispatch_async(dispatch_get_main_queue(), ^{
BOOL isError =NO;
if (isError) {
[subscribersendError:[NSErrorerrorWithDomain:@"cn.xzproject.error"code:1001userInfo:@{@"error message":@"异常错误"}]];
}else {
[subscribersendNext:_personList];
}
//发送完成事件
[subscribersendCompleted];
});
});
returnnil;
}];
}
ViewController.m
- (void)loadData {
// 1.实例化视图模型
_personListModel = [[XZPersonListModelalloc]init];
// 2.加载数据
/**
next是接收到数据
error接收到错误,错误处理
completed信号完成
*/
[[_personListModelloadPersons]subscribeNext:^(id _Nullable x) {
NSLog(@"==============%@",x);
//刷新数据
[self.tableNoticereloadData];
}error:^(NSError * _Nullable error) {
NSLog(@"==============%@",error);
}completed:^{
NSLog(@"==============完成");
}];
}
RAC-监听按钮和输入框事件
可以查看框架中的各种方法,RAC封装了常用的UI控件方法,需要监听哪个控件,查看一下这个控件或者他的父类的方法即可。
因为UIButton是继承自UIControl的,UIButton分类中没有合适的方法,所以,可以使用UIControl分类的方法
监听按钮的事件 -不再需要新建一个方法,在block里面实现相应事件,用block把重构的相关代码放在一起
[[btnrac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(__kindofUIControl *_Nullable x) {
NSLog(@"%@---------%@",x,[xclass]);
}];
// [btn rac_signalForControlEvents:UIControlEventTouchUpInside]是创建了一个冷信号,调用subscribeNext才订阅了信号,才会工作
监听文本输入框内容 -参数就是输入的文本内容!
[[nameTextFieldrac_textSignal]subscribeNext:^(NSString * _Nullable x) {
NSLog(@"%@ %@",x,[xclass]);
}];
组合信号
创建两个UITextField,将这两个的输入框的信号进行组合
UITextField *nameTextField = [[UITextFieldalloc]initWithFrame:CGRectMake(20,40,300,40)];
nameTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.viewaddSubview:nameTextField];
UITextField *pwdTextField = [[UITextFieldalloc]initWithFrame:CGRectMake(20,100,300,40)];
pwdTextField.borderStyle = UITextBorderStyleRoundedRect;
[self.viewaddSubview:pwdTextField];
//组合信号Tuple是元组,
[[RACSignalcombineLatest:@[nameTextField.rac_textSignal,pwdTextField.rac_textSignal]]subscribeNext:^(RACTuple * _Nullable x) {
NSString *name = x.first;
NSString *pwd = x.second;
NSLog(@"name:%@ pwd:%@ [x class]:%@",name,pwd,[xclass]);
//打印结果===name:Wertyui pwd:3456yui [x class]:RACTuple
}];
// reduce ->减少的意思,合并两个信号的数据,进行汇总计算时使用的!
// id是返回值,参数是有括号的;
// reduce中,可以通过接收的参数进行计算,并且返回需要的数值!例:登录界面,只有用户名和密码同时存在,才允许登录!
//方法一:使用__weak避免循环引用
// __weak typeof(self)weakSelf = self;
//方法二:
@weakify(self);
[[RACSignalcombineLatest:@[nameTextField.rac_textSignal,pwdTextField.rac_textSignal]reduce:^id(NSString *name, NSString *pwd){
NSLog(@"%@ %@",name,pwd);
//判断用户名和密码是否同时存在,需要转换成NSNumer类型,才能被当做 id 传递
return@(name.length > 0 && pwd.length > 0);
}]subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
@strongify(self);
self.btn.enabled = [x boolValue];
// weakSelf.btn.enabled = [x boolValue];
}];
}
// RAC在使用的时候,因为系统提供的信号是始终存在的!因此,所有的block中,如果出现'self.' / '成员变量'几乎百分之百会循环引用!
/**
解除循环引用的方法
1.__weak
2.利用 RAC 提供的 weak-strong dance
在 block的外部使用 @weakify(self)
在 block的内部使用 @strongify(self)
然后,直接使用self即可。
*/
//成员变量不好用weak
RAC4-使用RAC实现响应式编程
什么是响应式编程?
例,我们有3个变量,b = 3,c = 4, a = b + c = 7,如果这时我们修改b的值,让b=100,这时a的值不会发生变化,响应式编程就是当修改b或c的值时,a的值也会跟着变化。
在iOS开发中,可以使用 KVO 监听对象的属性值,达到这一效果!
因为苹果的 KVO会统一调用同一个方法,方法是固定的,如果监听属性过多,方法非常难以维护!
RAC是目前实现响应式编程的唯一解决方案!
MVVM:将“数据模型数据双向绑定”的思想作为核心,因此在View和Model之间没有联系,通过ViewModel进行交互,而且Model和ViewModel之间的交互是双向的,因此视图的数据的变化会同时修改数据源,而数据源数据的变化也会立即反应到View上。
代码实现
__weaktypeof(self)weakSelf = self;
//双向绑定
// 1>模型(KVO数据)绑定 UI(text属性)
// a) name(string) -> text(string)
RAC(nameTextField,text) = RACObserve(_person,name);
NSLog(@"RACObserve(_person, name):%@",RACObserve(_person,name));
// b) age(NSInteger) -> text(string),RAC中传递的数据都是 id 类型
//如果使用基本数据类型绑定 UI的内容,需要使用 map函数,通过 block对 value的数值进行转换之后,才能绑定
RAC(ageTextField,text) = [RACObserve(_person,age)map:^id_Nullable(id _Nullable value) {
NSLog(@"%@ %@",value,[valueclass]);
//错误的转换,value本身已经是 NSNumber,需要字符串
// return [NSString stringWithFormat:@"%zd",value];
return [valuedescription];
}];
// 2> UI绑定模型
[[RACSignalcombineLatest:@[nameTextField.rac_textSignal,ageTextField.rac_textSignal]]subscribeNext:^(RACTuple * _Nullable x) {
weakSelf.person.name = [x first];
weakSelf.person.age = [[x second]integerValue];
}];
// 3>添加按钮,输出结果
UIButton *btn = [UIButtonbuttonWithType:UIButtonTypeContactAdd];
btn.center = self.view.center;
[self.viewaddSubview:btn];
[[btnrac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(__kindofUIControl *_Nullable x) {
//循环引用!!!
NSLog(@"_person.name:%@ _person.age:%zd",weakSelf.person.name,weakSelf.person.age);
}];
}
阅读全文
0 0
- XZ_iOS之RAC(ReactiveCocoa)的介绍和使用
- XZ_iOS之pch的使用
- XZ_iOS之CocoaPods的安装和使用最新
- 开发中ReactiveCocoa的使用(RAC的属性监听)
- ReactiveCocoa之RAC常用宏(十)
- ReactiveCocoa之RAC内存管理(十二)
- ReactiveCocoa之RAC常用宏(十)
- iOS-ReactiveCocoa(RAC)的高级使用之视图与模型的双向绑定
- ReactiveCocoa之RAC映射(七)
- ReactiveCocoa之RAC过滤(八)
- ReactiveCocoa之RAC合并(九)
- ReactiveCocoa之RAC映射(七)
- ReactiveCocoa之RAC过滤(八)
- ReactiveCocoa之RAC合并(九)
- iOS-ReactiveCocoa(RAC)的初步了解以及基本使用
- iOS开发之ReactiveCocoa框架(RAC)第一篇
- XZ_iOS之collectionView的header和footer的重用
- XZ_iOS之时间戳和时间字符串的一个转换
- [题解]bzoj3295 CQOI2011动态逆序对
- java日期,时间戳相关应用
- java实现冒泡排序算法程序
- 记一次Centos6.7ssh免密钥登陆错误
- ffmpeg开发之旅(1):视频直播YUV颜色格式完全解析
- XZ_iOS之RAC(ReactiveCocoa)的介绍和使用
- 共享变量
- 安装SQLSERVER 2012 80端口被占用的问题
- java选择排序算法实现
- BOM浏览器,导航,弹窗,cookie,计时
- 创建表空间,创建用户,分配角色或权限
- CentOS7防火墙firewalld和iptable的设置和使用
- c#基础 类与结构体的区别 继承
- RocketMQ——Consumer端自动地不间断地发起拉取消息的业务逻辑