ReactiveCocoa是响应式编程(FRP)在iOS中的一个实现框架,它的开源地址为:https://github.com/ReactiveCocoa/ReactiveCocoa# ;在网上看了几篇文章,感受理论讲了不少,可是代码仍是看不太懂,因而本身把它github文档上的一些使用的经典示例实现了一下,项目中有须要时能够直接搬过去用,用的熟练了再读源码也比较容易理解。ios
例1. 监听对象的成员变量变化,当成员变量值被改变时,触发作一些事情。git
这种状况其实就是IOS KVO机制使用的场景,使用KVO实现,一般有三个步骤:1,给对象的成员变量添加监听;2,实现监听回调;3,取消监听;而经过RAC能够直接实现,RAC的回调是经过block实现的,相似于过程式编程,上下文也更容易理解一些。github
场景:当前类有一个成员变量 NSString *input,当它的值被改变时,发送一个请求。编程
实现: xcode
- [RACObserve(self, input)
- subscribeNext:^(NSString* x){
- request(x);
- }];
每次input值被修改时,就会调用此block,而且把修改后的值作为参数传进来。app
场景:在上面场景中,当用户输入的值以2开头时,才发请求.框架
实现:oop
- [[RACObserve(self, input)
- filter:^(NSString* value){
- if ([value hasPrefix:@"2"]) {
- return YES;
- } else {
- return NO;
- }
- }]
- subscribeNext:^(NSString* x){
- request(x);
- }];
场景:上面场景是监听本身的成员变量,若是想监听UITextField输入值变化,框架也作了封装能够代替系统回调spa
实现:.net
- [[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为可点击状态
实现:
- 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]);
- }];
场景:知足上面条件时,直接发送请求
实现:
- [[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秒延时在此方法中实现。
实现:
- - (void)showLoading {
-
- [self.loadingDispose dispose];
- @weakify(self);
- self.loadingDispose = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
- [subscriber sendCompleted];
- return nil;
- }] delay:1]
- subscribeCompleted:^{
- @strongify(self);
- doRequest();
- self.loadingDispose = nil;
- }];
- }
上面代码看起来挻费解,不过下面一段相似的代码拆开写的,会比较容易理解:
- [self.loadingDispose dispose];
-
- RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
- subscriptions++;
- [subscriber sendNext:@"mytest"];
- [subscriber sendCompleted];
- return nil;
- }];
-
- loggingSignal = [loggingSignal delay:10];
-
- self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){
- NSLog(@"%@",x);
- NSLog(@"subscription %u", subscriptions);
- }];
-
- self.loadingDispose = [loggingSignal subscribeCompleted:^{
- 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