一.RAC 是什么?能做什么?
1.RAC是Reactive Cocoa的简称,是一种支持函数式响应式编程的框架,由GitHub团队编写而成。
2.RAC可以做什么呢?
RAC通过信号的方式,链接组合和反应。通过一个统一的方法来处理异步行为,包括通知(NotificationCenter)、委托代理(Delegate)、目标操作机制(AddTarget)、KVO、回调Block。
也就是通过block的方式,来处理和简化这些异步行为。
3.版本大事件:
2.5以及之前版本不支持swift。
3.0版本ReactiveObjC是支持OC的最后一个版本。
4.0版本ReactiveSwift开始只支持swift。
二.为什么用RAC? 优缺点!
喜欢一个人,往往是从他身上的某个闪光点开始。
1.RAC有哪些闪光点?[需要进一步了解]
a.简洁高效,一行代码能解决的问题就不要用多行了(就不能写半行😆)
b.注册的通知,不需要释放,RAC内部帮你做了。
2.缺点
a.高耦合性
b.需要进一步了解
三.怎么使用ARC?
1.使用pod方式进行安装,GiTHub团队已经将支持OC和swift的支持库分开了,使用OC的可以
pod 'ReactiveObjC', '~> 3.0.0'
2.引入头文件
#import <ReactiveObjC/ReactiveObjC.h>
3.开始进入正题。
RAC是通过信号方式,链接组合和反应。所以要有三步,创建信号、监听信号、发送信号、(订阅信号)。
RAC发送信号包括了三种情况,下一步该做什么、成功之后做什么、失败(出错)之后该做什么。
// 创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 发送信号,有三种情况,下一步,出错、失败
[subscriber sendNext:@"RAC 我来了!"];
[subscriber sendError:nil];
[subscriber sendCompleted];
return nil;
}];
// 订阅信号 (也可以分开写)
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
} error:^(NSError * _Nullable error) {
NSLog(@"%@",error);
} completed:^{
NSLog(@"RAC 成功到达地球");
}];
// ----------------也可以简化写法-----------------------
// 创建信号
[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 发送信号
[subscriber sendNext:@"RAC 我来了!"];
return nil;
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
}];
4.避免循环引用,在block内部用self来引用控制器的成员变量, 可能会造成循环引用,这个时候在“外部用@weakify,内部用@strongify”这个方式来解决,如果直接用“_”来引用成员变量,可能会解决不了循环引用的问题
//问题:在信号中打印了控制器,也就是强引用了控制器,控制器中又强引用了信号,如下,就会形成循环应用
//信号外部用@weakify,内部用@strongify
@weakify(self)
RACSignal *signal = [[btn rac_signalForControlEvents:UIControlEventTouchUpInside]subscr subscribeNext:^(__kindof UIControl * _Nullable x) {
@strongify(self);
self.lable.text = @"这是来自RAC的信号!!!";
}];
self.signal = signal;
4.RAC中实现KVO
可以通过宏RACObserve来实现,绝壁一行代码,替代addObserver: forKeyPath:options: context:(void *)context
RAC中强大的宏,拿来小用一下Observe
#define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)
// 当对象self.dog的属性nickName发生变化时,就会调用这个block
[RACObserve(self.dog, nickName) subscribeNext:^(id _Nullable x) {
self.label.text = x; // x是subScribe发送的内容
}];
5.RAC中实现控件的事件(addTarget)
查看源码可以看到,其实RAC写了一个UIControl的分类 "UIControl+RACSignalSupport.h",在分类中完成了信号的三部曲,创建信号、订阅信号、发布信号。
[[self.btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
NSLog(@"使用RAC添加按钮事件!!!");
}];
6.RAC中有关控件,比较好玩的地方,真心推荐应该玩一下。
想用什么控件,就去RAC包中去找相关的扩展就好了,不多说,代码走起。。。比如监听UITextField的输入
// 传统方式监听UITextField的输入,需要很多代码,这里不多说,
// 使用ARC是怎么玩起来的呢?好吧,开始你的表演!别忘去哪里找?
// 去RAC包中有关UITextField的扩展,你会发现这个扩展其实都叫做
// RACSignalSupport
[[self.textField rac_textSignal] subscribeNext:^(NSString * _Nullable x) {
NSLog(@"textField==>text ==>%@",x);
}];
7.同时获取多个控件的变化,在RAC中就是将多个信号合并成一个信号进行处理,使用+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals
so easy!最好不要超过5个(因为限制了呢,证据在下面代码里)。
[[RACSignal combineLatest:@[self.textField.rac_textSignal,self.textField2.rac_textSignal]] subscribeNext:^(RACTuple * _Nullable x) {
NSString *name = x.first;
NSString *pwd = x.second;
NSLog(@"name===>%@,pwd===>%@",name,pwd);
}];
// --------------限制个数的证据在此--------------
typedef struct {
unsigned long state;
id __unsafe_unretained _Nullable * _Nullable itemsPtr;
unsigned long * _Nullable mutationsPtr;
unsigned long extra[5];
} NSFastEnumerationState;
// --------------限制个数的证据在此--------------
8.巧妙使用reduce,合并信号的数据,进行统计计算使用,例如判断手机号和密码同时存在,才可以点击登录按钮
[[RACSignal combineLatest:@[nameTextField.rac_textSignal, pwdTextField.rac_textSignal] reduce:^id _Nullable(NSString * name, NSString * pwd){
NSLog(@"%@ ,%@", name,pwd);
return @(name.length > 0 && pwd.length > 0);
return nil;
}] subscribeNext:^(id _Nullable x) {
NSLog(@"%@",x);
_demoButton.enabled = [x boolValue];
}];
备注: 如果pod安装,遇到一下错误
解决方法:在pod 'ReactiveCocoa’,’~>3.0’前面添加use_frameworks!
use_frameworks!
pod 'ReactiveCocoa’,’~>3.0’
原因:对于 Swift 项目,CocoaPods 提供了动态 Framework 的支持。通过 use_frameworks! 选项控制。对于 Swift 写的库来说,想通过 CocoaPods 引入工程,必须加入 use_frameworks! 选项。