iOS响应式编程框架ReactiveCocoa(RAC)
2016-11-29 16:11
106 查看
ReactiveCocoa是响应式编程(FRP)在iOS中的一个实现框架,它的开源地址为:https://github.com/ReactiveCocoa/ReactiveCocoa# ;在网上看了几篇文章,感觉理论讲了很多,但是代码还是看不太懂,于是自己把它github文档上的一些使用的经典示例实现了一下,项目中有需要时可以直接搬过去用,用的熟练了再读源码也比较容易理解。
例1. 监听对象的成员变量变化,当成员变量值被改变时,触发做一些事情。
这种情况其实就是IOS KVO机制使用的场景,使用KVO实现,通常有三个步骤:1,给对象的成员变量添加监听;2,实现监听回调;3,取消监听;而通过RAC可以直接实现,RAC的回调是通过block实现的,类似于过程式编程,上下文也更容易理解一些。
场景:当前类有一个成员变量 NSString *input,当它的值被改变时,发送一个请求。
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
[RACObserve(self, input) subscribeNext:^(NSString* x){ request(x);//发送一个请求 }];
![](http://static.blog.csdn.net/images/save_snippets.png)
每次input值被修改时,就会调用此block,并且把修改后的值做为参数传进来。
场景:在上面场景中,当用户输入的值以2开头时,才发请求.
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
[[RACObserve(self, input)
filter:^(NSString* value){
if ([value hasPrefix:@”2”]) {
return YES;
} else {
return NO;
}
}]
subscribeNext:^(NSString* x){
request(x);//发送一个请求
}];
![](http://static.blog.csdn.net/images/save_snippets.png)
场景:上面场景是监听自己的成员变量,如果想监听UITextField输入值变化,框架也做了封装可以代替系统回调
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
[[self.priceInput.rac_textSignal
filter:^(NSString *str) {
if (str.integerValue > 20) {
return YES;
} else {
 
4000
; return NO;
}
}]
subscribeNext:^(NSString *str) {
<span style=”white-space:pre”> </span>request(x);//发送一个请求
![](http://static.blog.csdn.net/images/save_snippets.png)
例2. 同时监听多个变量变化,当这些变量满足一定条件时,使button为可点击状态
场景:button监听 两个输入框有值和一个成员变量值,当输入框有输入且成员变量为真时,button为可点击状态
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
RAC(self.payButton,enabled) = [RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && [connect boolValue]); }];
![](http://static.blog.csdn.net/images/save_snippets.png)
场景:满足上面条件时,直接发送请求
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
[[RACSignal
combineLatest:@[self.priceInput.rac_textSignal,
self.nameInput.rac_textSignal,
RACObserve(self, isConnected)
]
reduce:^(NSString *price, NSString *name, NSNumber *connect){
return @(price.length > 0 && name.length > 0 && ![connect boolValue]);
}]
subscribeNext:^(NSNumber *res){
if ([res boolValue]) {
NSLog(@”XXXXX send request”);
}
}];
![](http://static.blog.csdn.net/images/save_snippets.png)
例3. 类似于生成产-消费
场景:用户每次在TextField中输入一个字符,1秒内没有其它输入时,去发一个请求。TextField中字符改变触发事件已在例1中展示,这里实现一下它触法的方法,把1秒延时在此方法中实现。
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
- (void)showLoading { [self.loadingDispose dispose];//上次信号还没处理,取消它(距离上次生成还不到1秒) @weakify(self); self.loadingDispose = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendCompleted]; return nil; }] delay:1] //延时一秒 subscribeCompleted:^{ @strongify(self); doRequest(); self.loadingDispose = nil; }]; }
![](http://static.blog.csdn.net/images/save_snippets.png)
上面代码看起来挻费解,不过下面一段类似的代码拆开写的,会比较容易理解:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
![](https://code.csdn.net/assets/ico_fork.svg)
[self.loadingDispose dispose];
RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {//BLOCK_1
subscriptions++;
[subscriber sendNext:@”mytest”];
[subscriber sendCompleted];
return nil;
}];
loggingSignal = [loggingSignal delay:10];
self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){//BLOCK_2
NSLog(@”%@”,x);
NSLog(@”subscription %u”, subscriptions);
}];
self.loadingDispose = [loggingSignal subscribeCompleted:^{//BLOCK_3
NSLog(@”subscription %u”, subscriptions);
}];
![](http://static.blog.csdn.net/images/save_snippets.png)
loggingSignal在每次被调用subscriibeNext:^(id x)或subscribeCompleted:^方法时(12行和17行),它创建进传进的参数block_1就会被触动发,而block_1中的sendNext:方法会调用subscriibeNext:^中对应的block_2, 而block_1中的sendCompleted会调用subscribeCompleted:中对应的block_3
例1. 监听对象的成员变量变化,当成员变量值被改变时,触发做一些事情。
这种情况其实就是IOS KVO机制使用的场景,使用KVO实现,通常有三个步骤:1,给对象的成员变量添加监听;2,实现监听回调;3,取消监听;而通过RAC可以直接实现,RAC的回调是通过block实现的,类似于过程式编程,上下文也更容易理解一些。
场景:当前类有一个成员变量 NSString *input,当它的值被改变时,发送一个请求。
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
[RACObserve(self, input) subscribeNext:^(NSString* x){ request(x);//发送一个请求 }];
![](http://static.blog.csdn.net/images/save_snippets.png)
[RACObserve(self, input) subscribeNext:^(NSString* x){ request(x);//发送一个请求 }];
每次input值被修改时,就会调用此block,并且把修改后的值做为参数传进来。
场景:在上面场景中,当用户输入的值以2开头时,才发请求.
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
[[RACObserve(self, input)
filter:^(NSString* value){
if ([value hasPrefix:@”2”]) {
return YES;
} else {
return NO;
}
}]
subscribeNext:^(NSString* x){
request(x);//发送一个请求
}];
![](http://static.blog.csdn.net/images/save_snippets.png)
[[RACObserve(self, input) filter:^(NSString* value){ if ([value hasPrefix:@"2"]) { return YES; } else { return NO; } }] subscribeNext:^(NSString* x){ request(x);//发送一个请求 }];
场景:上面场景是监听自己的成员变量,如果想监听UITextField输入值变化,框架也做了封装可以代替系统回调
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
[[self.priceInput.rac_textSignal
filter:^(NSString *str) {
if (str.integerValue > 20) {
return YES;
} else {
 
4000
; return NO;
}
}]
subscribeNext:^(NSString *str) {
<span style=”white-space:pre”> </span>request(x);//发送一个请求
![](http://static.blog.csdn.net/images/save_snippets.png)
[[self.priceInput.rac_textSignal filter:^(NSString *str) { if (str.integerValue > 20) { return YES; } else { return NO; } }] subscribeNext:^(NSString *str) { <span style="white-space:pre"> </span>request(x);//发送一个请求}];
例2. 同时监听多个变量变化,当这些变量满足一定条件时,使button为可点击状态
场景:button监听 两个输入框有值和一个成员变量值,当输入框有输入且成员变量为真时,button为可点击状态
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
RAC(self.payButton,enabled) = [RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && [connect boolValue]); }];
![](http://static.blog.csdn.net/images/save_snippets.png)
RAC(self.payButton,enabled) = [RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && [connect boolValue]); }];
场景:满足上面条件时,直接发送请求
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
[[RACSignal
combineLatest:@[self.priceInput.rac_textSignal,
self.nameInput.rac_textSignal,
RACObserve(self, isConnected)
]
reduce:^(NSString *price, NSString *name, NSNumber *connect){
return @(price.length > 0 && name.length > 0 && ![connect boolValue]);
}]
subscribeNext:^(NSNumber *res){
if ([res boolValue]) {
NSLog(@”XXXXX send request”);
}
}];
![](http://static.blog.csdn.net/images/save_snippets.png)
[[RACSignal combineLatest:@[self.priceInput.rac_textSignal, self.nameInput.rac_textSignal, RACObserve(self, isConnected) ] reduce:^(NSString *price, NSString *name, NSNumber *connect){ return @(price.length > 0 && name.length > 0 && ![connect boolValue]); }] subscribeNext:^(NSNumber *res){ if ([res boolValue]) { NSLog(@"XXXXX send request"); } }];
例3. 类似于生成产-消费
场景:用户每次在TextField中输入一个字符,1秒内没有其它输入时,去发一个请求。TextField中字符改变触发事件已在例1中展示,这里实现一下它触法的方法,把1秒延时在此方法中实现。
实现:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
- (void)showLoading { [self.loadingDispose dispose];//上次信号还没处理,取消它(距离上次生成还不到1秒) @weakify(self); self.loadingDispose = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendCompleted]; return nil; }] delay:1] //延时一秒 subscribeCompleted:^{ @strongify(self); doRequest(); self.loadingDispose = nil; }]; }
![](http://static.blog.csdn.net/images/save_snippets.png)
- (void)showLoading { [self.loadingDispose dispose];//上次信号还没处理,取消它(距离上次生成还不到1秒) @weakify(self); self.loadingDispose = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { [subscriber sendCompleted]; return nil; }] delay:1] //延时一秒 subscribeCompleted:^{ @strongify(self); doRequest(); self.loadingDispose = nil; }]; }
上面代码看起来挻费解,不过下面一段类似的代码拆开写的,会比较容易理解:
[objc] view plain copy print?
![](https://code.csdn.net/assets/CODE_ico.png)
[self.loadingDispose dispose];
RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {//BLOCK_1
subscriptions++;
[subscriber sendNext:@”mytest”];
[subscriber sendCompleted];
return nil;
}];
loggingSignal = [loggingSignal delay:10];
self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){//BLOCK_2
NSLog(@”%@”,x);
NSLog(@”subscription %u”, subscriptions);
}];
self.loadingDispose = [loggingSignal subscribeCompleted:^{//BLOCK_3
NSLog(@”subscription %u”, subscriptions);
}];
![](http://static.blog.csdn.net/images/save_snippets.png)
[self.loadingDispose dispose]; RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {//BLOCK_1 subscriptions++; [subscriber sendNext:@"mytest"]; [subscriber sendCompleted]; return nil; }]; loggingSignal = [loggingSignal delay:10]; self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){//BLOCK_2 NSLog(@"%@",x); NSLog(@"subscription %u", subscriptions); }]; self.loadingDispose = [loggingSignal subscribeCompleted:^{//BLOCK_3 NSLog(@"subscription %u", subscriptions); }];
loggingSignal在每次被调用subscriibeNext:^(id x)或subscribeCompleted:^方法时(12行和17行),它创建进传进的参数block_1就会被触动发,而block_1中的sendNext:方法会调用subscriibeNext:^中对应的block_2, 而block_1中的sendCompleted会调用subscribeCompleted:中对应的block_3
相关文章推荐
- 处理11gR2 RAC集群资源状态异常INTERMEDIATE,CHECK TIMED OUT
- rac 11gR2中 gsd 和 oc4j默认offline的解释
- 删除rac中ASM实例
- 一步一步在OEL5.5 64位Linux上安装Oracle 10gR2 RAC(5)
- 11gr2 RAC安装出现INS-35354
- 构建AIX环境下的RAC之--配置系统环境(1)
- error about Oracle 11g R2 RAC install at vmware
- 安装Oracle 10g RAC是否需要安装HACMP
- Configure Oracle 11gR2 RAC 一节点执行root.sh脚本报错
- Oracle 11g RAC 添加节点错误--数据库软件添加新节点故障
- vware server+redhat5.4+asm+rac
- 安装11.2.0.3 RAC grid 执行root.sh报错
- crsctl的使用 11gR2 RAC (start,stop,status:部分)
- 10g RAC 修改监听端口
- Oracle 11g R2 RAC 前置条件相关脚本
- 浅析RAC下SPFILE文件修改之整理三篇文章
- Oracle Rac clusterware startup sequence (11gR2)
- 用PXE方法从裸机批量推Oracle11gR2 RAC成套环境
- rac安装 错误1: `/tmp/bootstrap': Permission denied
- Oracle 单实例 迁移到 RAC 实例 -- 使用导出导入方法