RAC

2018-06-01  本文已影响0人  夜雨聲煩_

RP

概念

RP(Reactive Programming)——响应编程,实际上是异步事件流(Asynchronous event stream)。

根本

Stream

stream 流。一切都可以看成流,变量、用户输入、属性、事件、cache、数据结构。那么我们基于流,可以进行各种操作,combine,creat,filter,等等。对于流处理得到的数据又可以看做是新的流,以此进行不停的操作。

而对于一个流,包括三部分,即三个 events:value,error,complete。
当我们异步去捕获这些事件时,即为异步事件流。

如何捕获?我们采用监听的方式,去监听 stream,也成为订阅。定义的角色就是观察者,被监听的 stream 则是被观察者,其实也就是所谓的观察者模式

对 stream 操作

首先对于常见的 RP 库,对于 stream 都有很多方法,mapfilterscan等等,当时他们有一个共同的特点,就是返回值是一个新的 stream。

注意:
上文说的是产生新的stream,也就是说对初始的那个 stream 并没有做出修改,这个特性,就是不可变性(immutability)

新的 stream 可以继续进行相同的函数操作,这就是所谓的函数式编程

一个小例子

我们想在一连串的点击中检测例如鼠标点击那样的双击(包括三连击或者更高),间隔为250ms。

我首先想到的是获取点击时间点放入数组,遍历数组获取时间间隔放入数组,再遍历获取超过250ms的时间点的 index。再对应初始数组的位置取连击位置。略显复杂,且用到多个数组和遍历操作。
如果用流的方式的话...

用流的方式解决问题.png
使用throttle来设定有效时间,使用map来进行映射,使用filter进行筛选,最后生成的 stream 即是我们需要的新的 stream。我们可以通过订阅(监听)的方式来做出响应。

优美的逻辑和代码方式。

FRP

概念

函数响应式编程(英文Functional Reactive Programming),简称FRP。

特点
int a = 3;
int b = 4;
int c = a + b;
NSLog(@"c is %d", c); // c is 7
a = 5;
b = 7;
NSLog(@"c is %d", c); // 仍然是  c is 7

上面就是典型的命令式编程,通过表达式和语句来改变状态量,命令式编程int c = a + b;只是一个瞬间的过程,而并不是关系描述。在传统开发中,使c的值随a、b变化而变化是比较难的。

而响应式编程的出现就是为了描述这种实时变化的情况,也是响应式编程的核心思想。

// 代替target-action
    [[self.confirmButton rac_signalForControlEvents:UIControlEventTouchUpInside]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];
    
// 代替delegate
    [[self.scrollView rac_signalForSelector:@selector(scrollViewDidScroll:) fromProtocol:@protocol(UIScrollViewDelegate)]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];
    
// 代替block
    [[self asyncProcess]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     } error:^(NSError *error) {
        // 错误处理写到这里
     }];
    
// 代替notification center
    [[[NSNotificationCenter defaultCenter] rac_valuesForKeyPath:@"Some-key" observer:nil]
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];

// 代替KVO
    [RACObserve(self, userReportString)
     subscribeNext:^(id x) {
        // 回调内容写在这里
     }];

导入

OC版本:pod 'ReactiveObjC'
Swift版本:pod ‘ReactiveCocoa’

需要在podfile加上use_frameworks,重新pod install 才能导入成功

RAC接口

RACSignal

介绍:

信号,RP 中流概念(stream)在 RAC 中的对应,是贯穿 RAC 的核心概念,继承自 RACStream。

构造方法:

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe;
/// 冷信号
RACSignal *signal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) { 
    [subscriber sendNext:@"foobar"]; 
    [subscriber sendCompleted]; 
    return nil; 
}];
// Returns a signal that immediately completes.
+ (RACSignal<ValueType> *)empty RAC_WARN_UNUSED_RESULT;

普通方法:

//订阅后的冷信号变为热信号,改变时触发block中内容
[signal subscribeCompleted:^{ 
    NSLog(@"subscription %u", subscriptions); 
}]; 
- (RACSignal<ValueType> *)distinctUntilChanged RAC_WARN_UNUSED_RESULT;
//区别于searchText每次变化同时validSearchSignal被赋值
//加入distinctUntilChanged标记只有block内条件变化时validSearchSignal才被赋值。
  RACSignal *validSearchSignal =
    [[RACObserve(self, searchText)
      map:^id(NSString *text) {
          return @(text.length > 3);
      }]
     distinctUntilChanged];
- (RACSignal<ValueType> *)delay:(NSTimeInterval)interval RAC_WARN_UNUSED_RESULT;
/// Logs all events that the receiver sends.
- (RACSignal<ValueType> *)logAll RAC_WARN_UNUSED_RESULT;
RACCommand

介绍:

A command is a signal triggered in response to some action, typically UI-related.
UI Action 类型的一种信号

构造方法:

- (instancetype)initWithSignalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

- (instancetype)initWithEnabled:(nullable RACSignal<NSNumber *> *)enabledSignal signalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

enabled 决定该事件是否可用。
block 决定点击事件处理,block 中 Input 为点击事件传参,类似于 sender,返回的 RACSignal 为事件处理结果信号。

属性

A signal of whether this command is currently executing.

 //按钮点下搜索同时改变app状态栏中网络activity indicator
 RAC([UIApplication sharedApplication], networkActivityIndicatorVisible) = self.viewModel.executeSearch.executing;
上一篇 下一篇

猜你喜欢

热点阅读