IOS ReactiveCoCoa初学总结

本人刚学ios不久,然后研二找了大众点评公司的实习,岗位是ios,有幸接触了大众点评一些成熟的代码。里面大量运用了ReactiveCocoa这个东西,那么按我的理解说一说这个东西吧。

我们知道,我们平常处理一些事件,例如按键事件和一些编辑事件等等,我们一般使用的都是action,delegate,KVO,callback等等。这样有一个问题,不同的事件我们需要用到不同的事件处理。这样对于简单的事件操作是可以接受的,但是,如果你需要处理一系列的事间,如果每一个事件都需要做出相应的处理,如果用上述操作处理的话,往往会造成我们代码不一致,凌乱,活着事件逻辑不清晰等问题。而ReactiveCocoa就是用来解决上述的问题,他为每一个事件操作都提供了一致的接口。

ReactiveCocoa是函数响应式的编程框架(FRP), 具体例子如下。

RAC为不同的信号流提供了一个相同的接口,这个接口我们可以用统一的接口类来表示RACSignal,这个接口类我们可以用术语“信号”来称呼。

RAC的信号有3种类型,分别是error,next,complent.在RAC里面有很多的方法,用来订阅不同的事件类型,每一个方法里面都有一个block,用来执行事件类型的动作。例如:

ReactiveCocoa有很多操作来控制事件流。假设你只关心超过3个字符长度的用户名,那么你可以使用filter操作来实现这个目的。把之前加在viewDidLoad中的代码更新成下面的:

1
2
3
4
5
6
7
8
[[self.usernameTextField.rac_textSignal
filter:^BOOL(id value){
    NSString*text = value;
    return  text.length > 3;
}]
subscribeNext:^(id x){
    NSLog(@ "%@" , x);
   }];

编译运行,在text field只能怪输入几个字,你会发现只有当输入超过3个字符时才会有log。

1
2
3
4
5
6
7
8
9
10
11
2013-12-26 08:17:51.335 RWReactivePlayground[9654:a0b] is t
2013-12-26 08:17:51.478 RWReactivePlayground[9654:a0b] is th
2013-12-26 08:17:51.526 RWReactivePlayground[9654:a0b] is thi
2013-12-26 08:17:51.548 RWReactivePlayground[9654:a0b] is  this
2013-12-26 08:17:51.676 RWReactivePlayground[9654:a0b] is  this 
2013-12-26 08:17:51.798 RWReactivePlayground[9654:a0b] is  this  m
2013-12-26 08:17:51.926 RWReactivePlayground[9654:a0b] is  this  ma
2013-12-26 08:17:51.987 RWReactivePlayground[9654:a0b] is  this  mag
2013-12-26 08:17:52.141 RWReactivePlayground[9654:a0b] is  this  magi
2013-12-26 08:17:52.229 RWReactivePlayground[9654:a0b] is  this  magic
2013-12-26 08:17:52.486 RWReactivePlayground[9654:a0b] is  this  magic?

刚才所创建的只是一个很简单的管道。这就是响应式编程的本质,根据数据流来表达应用的功能。

用图形来表达就是下面这样的:

FilterPipeline.png

从上面的图中可以看到,rac_textSignal是起始事件。然后数据通过一个filter,如果这个事件包含一个长度超过3的字符串,那么该事件就可以通过。管道的最后一步就是subscribeNext:,block在这里打印出事件的值。

此外,还有一个用的 比较多的是RAC宏,这里我简要说明一下。他可以直接改变某个控件的属性。

首先要做的就是创建一些信号,来表示用户名和密码输入框中的输入内容是否有效。把下面的代码添加到RWViewController.m中viewDidLoad的最后面:

1
2
3
4
5
6
7
8
9
10
RACSignal *validUsernameSignal =
  [self.usernameTextField.rac_textSignal
  map:^id(NSString *text) {
  return  @([self isValidUsername:text]);
  }]; 
RACSignal *validPasswordSignal =
  [self.passwordTextField.rac_textSignal 
  map:^id(NSString *text) { 
  return  @([self isValidPassword:text]);
  }];

可以看到,上面的代码对每个输入框的rac_textSignal应用了一个map转换。输出是一个用NSNumber封装的布尔值。

下一步是转换这些信号,从而能为输入框设置不同的背景颜色。基本上就是,你订阅这些信号,然后用接收到的值来更新输入框的背景颜色。下面有一种方法:

1
2
3
4
5
6
7
[[validPasswordSignal
   map:^id(NSNumber *passwordValid){
     return [passwordValid boolValue] ? [UIColor clearColor]:[UIColor yellowColor];
   }]
   subscribeNext:^(UIColor *color){
     self.passwordTextField.backgroundColor = color;
   }];

(不要使用这段代码,下面有一种更好的写法!)

从概念上来说,就是把之前信号的输出应用到输入框的backgroundColor属性上。但是上面的用法不是很好。

幸运的是,ReactiveCocoa提供了一个宏来更好的完成上面的事情。把下面的代码直接加到viewDidLoad中两个信号的代码后面:

1
2
3
4
5
6
7
8
9
10
11
RAC(self.passwordTextField, backgroundColor) =
   [validPasswordSignal
     map:^id(NSNumber *passwordValid){
       return [passwordValid boolValue] ? [UIColor clearColor]:[UIColor yellowColor];
     }];
  
RAC(self.usernameTextField, backgroundColor) =
   [validUsernameSignal
     map:^id(NSNumber *passwordValid){
      return [passwordValid boolValue] ? [UIColor clearColor]:[UIColor yellowColor];
    }];

RAC宏允许直接把信号的输出应用到对象的属性上。RAC宏有两个参数,第一个是需要设置属性值的对象,第二个是属性名。每次信号产生一个next事件,传递过来的值都会应用到该属性上。

聚合信号是当需要两个事件同时响应处理时用的,她可以把两个信号合并为一个信号。例如:

现在的代码中已经有可以产生用户名和密码输入框是否有效的信号了——validUsernameSignal和validPasswordSignal了。现在需要做的就是聚合这两个信号来决定登录按钮是否可用。

把下面的代码添加到viewDidLoad的末尾:

1
2
3
4
5
RACSignal *signUpActiveSignal =
   [RACSignal combineLatest:@[validUsernameSignal, validPasswordSignal]
                     reduce:^id(NSNumber*usernameValid, NSNumber *passwordValid){
                       return  @([usernameValid boolValue]&&[passwordValid boolValue]);
                     }];

上面的代码使用combineLatest:reduce:方法把validUsernameSignal和validPasswordSignal产生的最新的值聚合在一起,并生成一个新的信号。每次这两个源信号的任何一个产生新值时,reduce block都会执行,block的返回值会发给下一个信号。

此外,还有个RACObserver这个方法,这个方法是通过KVO来监听某些属性的变化的,当方法里面某些属性发生变化,他block就回被调用一次。注意,有些类别不能使用这个方法,比如NSMutableArray,因为他不是基于KVO的,所以不能使用这个方法。

RACCommandz这个类是当需要处理某个按键处理时间使用的,使用这个方法,我们就不需要频繁的使用addTarget处理按键点击请求。

注意:RACsignal的这个方法可以聚合任意数量的信号,reduce block的参数和每个源信号相关。ReactiveCocoa有一个工具类RACBlockTrampoline,它在内部处理reduce block的可变参数。实际上在ReactiveCocoa的实现中有很多隐藏的技巧,值得你去看看。

好了,就这么多了,谢谢。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值