函数式 响应编程
 

ReactiveCocoa的基本使用方法

ReactiveCocoa是github一个开源项目,是在iOS平台上对FRP的实现。FRP的核心是信号,信号在ReactiveCocoa(以下简称RAC)中是通过RACSignal来表示的,信号是数据流,可以被绑定和传递。

可以把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列,不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。可以在水龙头上加一个过滤嘴(filter),不符合的不让通过,也可以加一个改动装置,把球改变成符合自己的需求(map)。也可以把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样只要其中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。

 

RAC统一了对KVO、UI Event、Network request、Async work的处理,因为它们本质上都是值的变化(Values over time)。

 

替代KVO

@property(strong) NSString *username;
[RACObserve(self,username) subscribeNext:^(NSString *newName){
    NSLog(@"%@",newName);
}];

只要username发生变化就打印出来。体现绑定和响应。

[[RACObserver(self,username) filter:^(NSString *newName) {
   return [newName hasPrefix:@"j"];
}] subscribeNext:^(NSString *newName) {
   NSLog(@"%@",newName);
}

增加一个过滤器

 

替代selector

1
2
3
4
self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
    NSLog(@"button was pressed!");
    return [RACSignal empty];
}];

 

流的实现

1
2
3
4
5
RAC(self, timeLabel.text) = [[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] startWith:[NSDate date]] map:^id (NSDate *value) {
   NSLog(@"value:%@", value);
   NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSHourCalendarUnit |NSMinuteCalendarUnit NSSecondCalendarUnit fromDate:value];
  return [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)dateComponents.hour, (long)dateComponents.minute, (long)dateComponents.second];
}];

  

组合

1
2
3
RAC(self, submitButton.enabled) = [RACSignal combineLatest:@[self.usernameField.rac_textSignal, self.passwordField.rac_textSignal] reduce:^id (NSString *userName, NSString *password) {
  return @(userName.length >= 6 && password.length >= 6);
}];

将usernameField和passwordField的信号绑定在一起做reduce处理。返回一个BOOL值去跟self.submitButton.enabled进绑定。


网络请求

1
2
3
self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) {
    return [client logIn];
}];<br><br>[self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {<br>  [loginSignal subscribeCompleted:^{<br>    NSLog(@"Logged in successfully!");<br>  }];<br>}];

  

ReactiveCocoa的基本使用方法

ReactiveCocoa是github一个开源项目,是在iOS平台上对FRP的实现。FRP的核心是信号,信号在ReactiveCocoa(以下简称RAC)中是通过RACSignal来表示的,信号是数据流,可以被绑定和传递。

可以把信号想象成水龙头,只不过里面不是水,而是玻璃球(value),直径跟水管的内径一样,这样就能保证玻璃球是依次排列,不会出现并排的情况(数据都是线性处理的,不会出现并发情况)。水龙头的开关默认是关的,除非有了接收方(subscriber),才会打开。这样只要有新的玻璃球进来,就会自动传送给接收方。可以在水龙头上加一个过滤嘴(filter),不符合的不让通过,也可以加一个改动装置,把球改变成符合自己的需求(map)。也可以把多个水龙头合并成一个新的水龙头(combineLatest:reduce:),这样只要其中的一个水龙头有玻璃球出来,这个新合并的水龙头就会得到这个球。

 

RAC统一了对KVO、UI Event、Network request、Async work的处理,因为它们本质上都是值的变化(Values over time)。

 

替代KVO

@property(strong) NSString *username;
[RACObserve(self,username) subscribeNext:^(NSString *newName){
    NSLog(@"%@",newName);
}];

只要username发生变化就打印出来。体现绑定和响应。

[[RACObserver(self,username) filter:^(NSString *newName) {
   return [newName hasPrefix:@"j"];
}] subscribeNext:^(NSString *newName) {
   NSLog(@"%@",newName);
}

增加一个过滤器

 

替代selector

1
2
3
4
self.button.rac_command = [[RACCommand alloc] initWithSignalBlock:^(id _) {
    NSLog(@"button was pressed!");
    return [RACSignal empty];
}];

 

流的实现

1
2
3
4
5
RAC(self, timeLabel.text) = [[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] startWith:[NSDate date]] map:^id (NSDate *value) {
   NSLog(@"value:%@", value);
   NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSHourCalendarUnit |NSMinuteCalendarUnit NSSecondCalendarUnit fromDate:value];
  return [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)dateComponents.hour, (long)dateComponents.minute, (long)dateComponents.second];
}];

  

组合

1
2
3
RAC(self, submitButton.enabled) = [RACSignal combineLatest:@[self.usernameField.rac_textSignal, self.passwordField.rac_textSignal] reduce:^id (NSString *userName, NSString *password) {
  return @(userName.length >= 6 && password.length >= 6);
}];

将usernameField和passwordField的信号绑定在一起做reduce处理。返回一个BOOL值去跟self.submitButton.enabled进绑定。


网络请求

1
2
3
self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^(id sender) {
    return [client logIn];
}];<br><br>[self.loginCommand.executionSignals subscribeNext:^(RACSignal *loginSignal) {<br>  [loginSignal subscribeCompleted:^{<br>    NSLog(@"Logged in successfully!");<br>  }];<br>}];