iOS【ReactiveCocoa的使⽤(RAC的属性监听)】
前⾔
很多blog都说ReactiveCocoa好⽤,然后各种秀⾃⼰如何灵活运⽤ReactiveCocoa,但是感觉真正缺少的是⼀篇如何学习ReactiveCocoa的⽂章,⼩编看了很多篇都没看出怎么使⽤ReactiveCocoa,于是决定⾃⼰写⼀遍关于学习ReactiveCocoa的⽂章,本⽂主要针对如何从零开始学习ReactiveCocoa
1.ReactiveCocoa简介
ReactiveCocoa(简称为RAC),是由Github开源的⼀个应⽤于iOS和OS开发的新框架,Cocoa是苹果整套框架的简称,因此很多苹果框架喜欢以Cocoa结尾。
2.ReactiveCocoa作⽤
在我们iOS开发过程中,当某些事件响应的时候,需要处理某些业务逻辑,这些事件都⽤不同的⽅式来处理。
悲痛的反义词⽐如按钮的点击使⽤action,ScrollView滚动使⽤delegate,属性值改变使⽤KVO等系统提供的⽅式。
其实这些事件,都可以通过RAC处理
ReactiveCocoa为事件提供了很多处理⽅法,⽽且利⽤RAC处理事件很⽅便,可以把要处理的事情,和监听的事情的代码放在⼀起,这样⾮常⽅便我们管理,就不需要跳到对应的⽅法⾥。⾮常符合我们开发中⾼聚合,低耦合的思想。
3.编程思想
在开发中我们也不能太依赖于某个框架,否则这个框架不更新了,导致项⽬后期没办法维护,⽐如之前Facebook提供的Three20框架,在当时也是神器,但是后来不更新了,也就没什么⼈⽤了。因此我感觉学习⼀个框架,还是有必要了解它的编程思想。
先简单介绍下⽬前咱们已知的编程思想。
3.1 ⾯向过程:处理事情以过程为核⼼,⼀步⼀步的实现。
广东大排档3.2 ⾯向对象:万物皆对象
3.3 链式编程思想:是将多个操作(多⾏代码)通过点号(.)链接在⼀起成为⼀句代码,使代码可读性好。a(1).b(2).c(3)
链式编程特点:⽅法的返回值是block,block必须有返回值(本⾝对象),block参数(需要操作的值)
代表:masonry框架。
模仿masonry,写⼀个加法计算器,练习链式编程思想。
3.4 响应式编程思想:不需要考虑调⽤顺序,只需要知道考虑结果,类似于蝴蝶效应,产⽣⼀个事件,会影响很多东西,这些事件像流⼀样的传播出去,然后影响结果,借⽤⾯向对象的⼀句话,万物皆是流。
诚信成语代表:KVO运⽤。
3.5 函数式编程思想:是把操作尽量写成⼀系列嵌套的函数或者⽅法调⽤。
函数式编程特点:每个⽅法必须有返回值(本⾝对象),把函数或者Block当做参数,block参数(需要操作的值)block返回值(操作结果)
代表:ReactiveCocoa。
⽤函数式编程实现,写⼀个加法计算器,并且加法计算器⾃带判断是否等于某个值.
Paste_Image.png
Paste_Image.png
4.ReactiveCocoa编程思想
ReactiveCocoa结合了⼏种编程风格:
函数式编程(Functional Programming)
响应式编程(Reactive Programming)
所以,你可能听说过ReactiveCocoa被描述为函数响应式编程(FRP)框架。
以后使⽤RAC解决问题,就不需要考虑调⽤顺序,直接考虑结果,把每⼀次操作都写成⼀系列嵌套的⽅法中,使代码⾼聚合,⽅便管理。
蒜泥肘子
5.如何导⼊ReactiveCocoa框架
通常都会使⽤CocoaPods(⽤于管理第三⽅框架的插件)帮助我们导⼊。
PS:
天气很好阳光很美句子注意:
podfile如果只描述pod 'ReactiveCocoa', '~> 4.0.2-alpha-1',会导⼊不成功。
Snip20150926_1.png
报错提⽰信息
Snip20150926_2.png
需要在podfile加上u_frameworks,重新pod install 才能导⼊成功。
Snip20150926_3.png
6.ReactiveCocoa常见类。
学习框架⾸要之处:个⼈认为先要搞清楚框架中常⽤的类,在RAC中最核⼼的类RACSiganl,搞定这个类就能⽤ReactiveCocoa开发了。
6.1RACSiganl:信号类,⼀般表⽰将来有数据传递,只要有数据改变,信号内部接收到数据,就会马上发出数据。
注意:
信号类(RACSiganl),只是表⽰当数据改变时,信号内部会发出数据,它本⾝不具备发送信号的能⼒,⽽是交给内部⼀个订阅者去发出。
默认⼀个信号都是冷信号,也就是值改变了,也不会触发,只有订阅了这个信号,这个信号才会变为热信号,值改变了才会触发。
如何订阅信号:调⽤信号RACSignal的subscribeNext就能订阅。
RACSiganl简单使⽤:
// RACSignal使⽤步骤:
// 1.创建信号 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
// 2.订阅信号,才会激活信号. - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.发送信号 - (void)ndNext:(id)value
// RACSignal底层实现:
/
/ 1.创建信号,⾸先把didSubscribe保存到信号中,还不会触发。
// 2.当信号被订阅,也就是调⽤signal的subscribeNext:nextBlock
// 2.2 subscribeNext内部会创建订阅者subscriber,并且把nextBlock保存到subscriber中。
// 2.1 subscribeNext内部会调⽤siganl的didSubscribe
// 3.siganl的didSubscribe中调⽤[subscriber ndNext:@1];
// 3.1 ndNext底层其实就是执⾏subscriber的nextBlock
// 1.创建信号
RACSignal *siganl = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// block调⽤时刻:每当有订阅者订阅信号,就会调⽤block。
// 2.发送信号
[subscriber ndNext:@1];
/
/ 如果不在发送数据,最好发送信号完成,内部会⾃动调⽤[RACDisposable disposable]取消订阅信号。
[subscriber ndCompleted];
return [RACDisposable disposableWithBlock:^{
// block调⽤时刻:当信号发送完成或者发送错误,就会⾃动执⾏这个block,取消订阅信号。
// 执⾏完Block后,当前信号就不在被订阅了。
NSLog(@"信号被销毁");
}];
}];
// 3.订阅信号,才会激活信号.
[siganl subscribeNext:^(id x) {
// block调⽤时刻:每当有信号发出数据,就会调⽤block.
NSLog(@"接收到数据:%@",x);
}];
6.2 RACSubscriber:表⽰订阅者的意思,⽤于发送信号,这是⼀个协议,不是⼀个类,只要遵守这个协议,并且实现⽅法才能成为订阅者。通过create创建的信号,都有⼀个订阅者,帮助他发送数据。
6.3 RACDisposable:⽤于取消订阅或者清理资源,当信号发送完成或者发送错误的时候,就会⾃动触发它。
使⽤场景:不想监听某个信号时,可以通过它主动取消订阅信号。
6.4 RACSubject:RACSubject:信号提供者,⾃⼰可以充当信号,⼜能发送信号。
使⽤场景:通常⽤来代替代理,有了它,就不必要定义代理了。
RACReplaySubject:重复提供信号类,RACSubject的⼦类。
RACReplaySubject与RACSubject区别:
RACReplaySubject可以先发送信号,在订阅信号,RACSubject就不可以。
使⽤场景⼀:如果⼀个信号每被订阅⼀次,就需要把之前的值重复发送⼀遍,使⽤重复提供信号类。
使⽤场景⼆:可以设置capacity数量来限制缓存的value的数量,即只缓充最新的⼏个值。
RACSubject和RACReplaySubject简单使⽤:
// RACSubject使⽤步骤
// 1.创建信号 [RACSubject subject],跟RACSiganl不⼀样,创建信号时没有block。
// 2.订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 3.发送信号 ndNext:(id)value
// RACSubject:底层实现和RACSignal不⼀样。
// 1.调⽤subscribeNext订阅信号,只是把订阅者保存起来,并且订阅者的nextBlock已经赋值了。
// 2.调⽤ndNext发送信号,遍历刚刚保存的所有订阅者,⼀个⼀个调⽤订阅者的nextBlock。
/
/ 1.创建信号
RACSubject *subject = [RACSubject subject];
// 2.订阅信号
[subject subscribeNext:^(id x) {
// block调⽤时刻:当信号发出新值,就会调⽤.
NSLog(@"第⼀个订阅者%@",x);
}];
[subject subscribeNext:^(id x) {
// block调⽤时刻:当信号发出新值,就会调⽤.
NSLog(@"第⼆个订阅者%@",x);
}];
/
/ 3.发送信号
[subject ndNext:@"1"];
// RACReplaySubject使⽤步骤:
// 1.创建信号 [RACSubject subject],跟RACSiganl不⼀样,创建信号时没有block。化学世界
// 2.可以先订阅信号,也可以先发送信号。
// 2.1 订阅信号 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
// 2.2 发送信号 ndNext:(id)value
// RACReplaySubject:底层实现和RACSubject不⼀样。
// 1.调⽤ndNext发送信号,把值保存起来,然后遍历刚刚保存的所有订阅者,⼀个⼀个调⽤订阅者的nextBlock。 // 2.调⽤subscribeNext订阅信号,遍历保存的所有值,⼀个⼀个调⽤订阅者的nextBlock
// 如果想当⼀个信号被订阅,就重复播放之前所有值,需要先发送信号,在订阅信号。
// 也就是先保存值,在订阅值。
// 1.创建信号
RACReplaySubject *replaySubject = [RACReplaySubject subject];
// 2.发送信号
[replaySubject ndNext:@1];
[replaySubject ndNext:@2];
// 3.订阅信号
[replaySubject subscribeNext:^(id x) {
NSLog(@"第⼀个订阅者接收到的数据%@",x);
}];
// 订阅信号
[replaySubject subscribeNext:^(id x) {
NSLog(@"第⼆个订阅者接收到的数据%@",x);
}];
RACSubject替换代理
// 需求:
// 1.给当前控制器添加⼀个按钮,modal到另⼀个控制器界⾯
// 2.另⼀个控制器view中有个按钮,点击按钮,通知当前控制器
步骤⼀:在第⼆个控制器.h,添加⼀个RACSubject代替代理。
@interface TwoViewController : UIViewController
羸弱读音@property (nonatomic, strong) RACSubject *delegateSignal;
@end
步骤⼆:监听第⼆个控制器按钮点击
@implementation TwoViewController
- (IBAction)notice:(id)nder {
// 通知第⼀个控制器,告诉它,按钮被点了
眉清目秀造句
// 通知代理
// 判断代理信号是否有值
if (lf.delegateSignal) {
// 有值,才需要通知
[lf.delegateSignal ndNext:nil];
}
}
@end
步骤三:在第⼀个控制器中,监听跳转按钮,给第⼆个控制器的代理信号赋值,并且监听.
@implementation OneViewController
- (IBAction)btnClick:(id)nder {
// 创建第⼆个控制器
TwoViewController *twoVc = [[TwoViewController alloc] init];
// 设置代理信号
twoVc.delegateSignal = [RACSubject subject];
// 订阅代理信号
[twoVc.delegateSignal subscribeNext:^(id x) {
NSLog(@"点击了通知按钮");
}];
// 跳转到第⼆个控制器
[lf prentViewController:twoVc animated:YES completion:nil];
}
@end
6.6RACTuple:元组类,类似NSArray,⽤来包装值.
6.7RACSequence:RAC中的集合类,⽤于代替NSArray,NSDictionary,可以使⽤它来快速遍历数组和字典。使⽤场景:1.字典转模型
RACSequence和RACTuple简单使⽤
// 1.遍历数组
NSArray *numbers = @[@1,@2,@3,@4];
// 这⾥其实是三步
// 第⼀步: 把数组转换成集合RACSequence numbers.rac_quence
// 第⼆步: 把集合RACSequence转换RACSignal信号类,numbers.rac_quence.signal
// 第三步: 订阅信号,激活信号,会⾃动把集合中的所有值,遍历出来。
[numbers.rac_quence.signal subscribeNext:^(id x) {