2020-07-22RAC

2020-07-22  本文已影响0人  我是小胡胡分胡

大大盆子

https://www.jianshu.com/p/8dbe8878d1c5

前言

之前对RAC有了一个基本的认识,了解了它的作用,以及RAC的运行机制,我们知道只要是信号(RACSignal),我们就能对它进行一顿订阅,然后执行触发操作;接下来我们来学习一下RAC中常用的类以及一系列的用法。


RACSignal

这是一个信号类,表示一个信号源,只要有数据改变就会把数据包装成信号传递出去,它本身不具备发送信号的能力,而是交给内部的一个订阅者(RACSubscriber)去发出,然后当信号被订阅之后,就会在其内部就创建一个订阅者,所以在信号内部就可以发送信号了,之前也对RACSignal做了一个简单的了解,下面学习一下更多的用法

 [[btn rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        //x==btn
        NSLog(@"%@",x);
        [self push];
 }];

//因为订阅信号是void返回类型的,所以只能代替void返回类型的delegate
[textField.rac_textSignal subscribeNext:^(NSString * _Nullable x) {
        //x==textField.text
        NSLog(@"%@",x);
}];

//直接用宏
[RACObserve(self.view, backgroundColor) subscribeNext:^(id  _Nullable x) {
        //x==新背景颜色
        NSLog(@"%@",x);
 }];
//也可以这样
__weak typeof(self) weakSelf = self;
 [[self.view rac_valuesForKeyPath:@"backgroundColor" observer:weakSelf] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
 }];

[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIKeyboardWillShowNotification object:nil] subscribeNext:^(NSNotification * _Nullable x) {
        //x==userInfo
        NSLog(@"%@",x);
 }];

//map,将输出NSNumber的signal转换成输出NSString
RACSignal *mapSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        [subscriber sendNext:@(1)];
        return nil;
    }] map:^id _Nullable(id  _Nullable value) {

        return [NSString stringWithFormat:@"%@",value];
    }];
    [mapSignal subscribeNext:^(id  _Nullable x) {
        //NSString类型
        NSLog(@"x");
    }];

//flattenMap,将输出NSNumber的signal转换成输出NSString
RACSignal *mapSignal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;

    }] flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {

        return [RACReturnSignal return:[NSString stringWithFormat:@"%@",value]];
    }];
    [mapSignal subscribeNext:^(id  _Nullable x) {
        //NSString类型
        NSLog(@"x");
    }];

两者之间的区别就在于,map中Block返回转换对象,flattenMap返回转换对象的信号。一般信号发出的值不是信号,使用map;如果是信号则使用flattenMap,它可以处理信号中的信号。

RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        return nil;
    }];
    RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(3)];
        return nil;
    }];
    RACSignal *mergeSignal = [RACSignal merge:@[signal1,signal2,signal3]];
    [mergeSignal subscribeNext:^(id  _Nullable x) {
        //分别输出1,2,3
        NSLog(@"%@",x);
    }];

RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        //发送信号完成,表示不再订阅了,内部会自动调用[RACDisposable disposable]取消订阅信号。
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *signal3 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(3)];
        [subscriber sendCompleted];
        return nil;
    }];
    RACSignal *concatSignal = [RACSignal concat:@[signal2,signal1,signal3]];
    [concatSignal subscribeNext:^(id  _Nullable x) {
        //分别输出2,1,3
        NSLog(@"%@",x);
    }];

    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendCompleted];
        return nil;
    }];
   RACSignal *thenSignal =  [signal1 then:^RACSignal * _Nonnull{
      return  [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
           [subscriber sendNext:@(2)];
           [subscriber sendCompleted];
           return nil;
       }];
   }];
    [thenSignal subscribeNext:^(id  _Nullable x) {
        //输出2
        NSLog(@"%@",x);
    }];

    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        //不会覆盖上一个信号
        [subscriber sendNext:@(3)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {

        [subscriber sendNext:@(2)];
        return nil;
    }] ;
    RACSignal *zipSignal = [RACSignal zip:@[signal1,signal2]];
    [zipSignal subscribeNext:^(id  _Nullable x) {
        //输出(1,2)
        NSLog(@"%@",x);
    }];

    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        //将覆盖之前的信号,这就是跟zip的区别
        [subscriber sendNext:@(3)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        return nil;
    }];
   //如果其中一个信号不sendNext,则不会触发组合信号
    RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] ];
    [combineSignal subscribeNext:^(id  _Nullable x) {
        //输出(3,2)
        NSLog(@"%@",x);
    }];

    RACSubject *subject1 = [RACSubject subject];
    RACSubject *subject2 = [RACSubject subject];
    [[self rac_liftSelector:@selector(updateWithParameter1:parameter2:) withSignals:subject1,subject2, nil] subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    [subject1 sendNext:@1];
    [subject2 sendNext:@2];

RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] ];
    RACSignal *reduceSignal = [combineSignal reduceEach:^id (NSNumber *num1,NSNumber *num2){
        return @(num1.doubleValue+num2.doubleValue);
    }];
    [reduceSignal subscribeNext:^(id  _Nullable x) {
        //输出3
        NSLog(@"%@",x);
    }];
//等同于+ (RACSignal *)combineLatest:(id<NSFastEnumeration>)signals reduce:(id (^)())reduceBlock
//    RACSignal *combineSignal = [RACSignal combineLatest:@[signal1,signal2] reduce:^id (NSNumber *num1,NSNumber *num2){
//        return @(num1.doubleValue+num2.doubleValue);
//    }];

RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@"3"];
        return nil;
    }];
    RACSignal *filterSignal = [signal1 filter:^BOOL(id  _Nullable value) {
        return [value isKindOfClass:[NSNumber class]];
    }];
    [filterSignal subscribeNext:^(id  _Nullable x) {
        //输出1
        NSLog(@"%@",x);
    }];

    //数组的筛选
    RACSequence *sequence = [@[@(1),@(2),@"3"].rac_sequence filter:^BOOL(id  _Nullable value) {
        return [value isKindOfClass:[NSNumber class]];
    }];
    [sequence.signal subscribeNext:^(id  _Nullable x) {
        //输出1,2
        NSLog(@"%@",x);
    }];

[textField.rac_textSignal.distinctUntilChanged subscribeNext:^(NSString * _Nullable x) {
        //变化时输出变化之后的值
        NSLog(@"%@",x);
    }];

    RACSignal *signal = [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@(2)];
        return nil;
    }] take:1];

    [signal subscribeNext:^(id  _Nullable x) {
        //输出1,因为take为1,所以有效的只有最开始的那一个,其他的忽略掉了
        NSLog(@"%@",x);
    }];

    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@(2)];
        [subscriber sendCompleted];
        return nil;
    }] takeLast:1] subscribeNext:^(id  _Nullable x) {
        //输出2
        NSLog(@"%@",x);
    }];

    RACSignal *signal1 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }];
    RACSignal *signal2 = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(2)];
        return nil;
    }];
    [[signal1 takeUntil:signal2] subscribeNext:^(id  _Nullable x) {
        //什么都不会输出,因为signal2已经sendNext,所以signal1就会失效
        NSLog(@"%@",x);
    }];

[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        [subscriber sendNext:@(2)];
        [subscriber sendNext:@(3)];
        return nil;
    }] skip:2] subscribeNext:^(id  _Nullable x) {
        //输出3
        NSLog(@"%@",x);
    }];

[[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }] doNext:^(id  _Nullable x) {
        x = [NSString stringWithFormat:@"%@haha",x];
        //输出1haha,在订阅回调之前执行
        NSLog(@"%@",x);
    }] subscribeNext:^(id  _Nullable x) {
        //输出1
        NSLog(@"%@",x);
    }];

    RACSubject *subject = [RACSubject subject];
    [[subject timeout:3 onScheduler:[RACScheduler mainThreadScheduler]] subscribeNext:^(id  _Nullable x) {
        //只输出1
        NSLog(@"%@",x);
    } error:^(NSError * _Nullable error) {
        //3秒之后输出错误日志
        NSLog(@"%@",error);
    }];
    [subject sendNext:@1];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [subject sendNext:@2];
    });

//RACScheduler:队列
[[RACSignal interval:1 onScheduler:[RACScheduler currentScheduler]] subscribeNext:^(NSDate * _Nullable x) {
        //每隔一秒输出当前时间
        NSLog(@"%@",x);
}];

    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@(1)];
        return nil;
    }] delay:3] subscribeNext:^(id  _Nullable x) {
        //3秒之后输出1
        NSLog(@"%@",x);
    }];

    __block NSInteger i = 0;
    [[[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        i++;
        if (i > 10) {
            [subscriber sendNext:@(1)];
        }else{
            [subscriber sendError:nil];
        }
        return nil;
    }] retry] subscribeNext:^(id  _Nullable x) {
        //重试10次之后输出1
        NSLog(@"%@",x);
    }error:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];

    RACSubject *subject = [RACSubject subject];
// [subject bufferWithTime:1 onScheduler:[RACScheduler currentScheduler]];
    [[subject throttle:1] subscribeNext:^(id  _Nullable x) {
        //输出3,拿到最后发出的内容3
        NSLog(@"%@",x);
    }];
    [subject sendNext:@1];
    [subject sendNext:@2];
    [subject sendNext:@3];


RACSubject

信号提供者,本身可以充当信号,又能发送信号,继承自RACSignal,但是底层实现跟RACSignal有些不一样,当订阅信号的时候会创建订阅者并保存订阅响应Block,而发送信号的时候会遍历订阅者,然后分别调用nextBlock。它提供的API很少,但是经常使用,因为它继承自RACSignal。这里顺便来看一下方法 flattenswitchToLatest,这两个都只能用来处理信号中的信号。

RACSubject *subject = [RACSubject subject];
RACSubject *subSubject1 = [RACSubject subject];
RACSubject *subSubject2 = [RACSubject subject];
[subject subscribeNext:^(id  _Nullable x) {
    //分别输出subSubject1,subSubject2,但是不能拿到其中的值
    NSLog(@"%@",x);
}];
[subject.flatten subscribeNext:^(id  _Nullable x) {
    //分别输出1,2, flatten可以拿到所有子信号发送的值
    NSLog(@"%@",x);
}];
[subject sendNext:subSubject1];
[subject sendNext:subSubject2];
[subSubject1 sendNext:@1];
[subSubject2 sendNext:@2];

RACSubject *subject = [RACSubject subject];
RACSubject *subSubject1 = [RACSubject subject];
RACSubject *subSubject2 = [RACSubject subject];
[subject subscribeNext:^(id  _Nullable x) {
    //分别输出subSubject1,subSubject2,但是不能拿到其中的值
    NSLog(@"%@",x);
}];
[subject.switchToLatest subscribeNext:^(id  _Nullable x) {
    //输出2, switchToLatest只会拿到最新的子信号发送的值
    NSLog(@"%@",x);
}];
[subject sendNext:subSubject1];
[subject sendNext:subSubject2];
[subSubject1 sendNext:@1];
[subSubject2 sendNext:@2];

RACReplaySubject

重复提供信号类,继承自RACSubject,它可以先发送信号,再订阅信号,原理就是将发送的信号内容保存了起来,当订阅信号的时候再将之前保存的信号,由订阅者一个一个的发送出来,而保存信号的容量由capacity来控制。

 RACReplaySubject *replaySubject = [RACReplaySubject replaySubjectWithCapacity:5];
 [replaySubject subscribeNext:^(id  _Nullable x) {
     //输出1
     NSLog(@"%@",x);
 }];
 [replaySubject sendNext:@1];
 [replaySubject subscribeNext:^(id  _Nullable x) {
     //输出1
     NSLog(@"%@",x);
 }];


RACMulticastConnection

这是一个组播连接类,是对信号的一个封装处理,当一个信号被多次订阅时,则会多次执行didSubscribe这个Block,造成副作用,而这个类就能避免多次执行didSubscribe,是一对多的单向数据流,一般用来处理信号被多次订阅的情况。

__block int i = 0;
//创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
    [subscriber sendNext:@(i)];
    i ++;
    return nil;
}];
//创建RACMulticastConnection对象
RACMulticastConnection *connect = [signal publish]
 [connect.signal subscribeNext:^(id  _Nullable x) {
    //输出0
    NSLog(@"%@",x);
}];
[connect.signal subscribeNext:^(id  _Nullable x) {
    //输出0,当再次订阅时,不会再执行didSubscribe,所以并没有i++
    NSLog(@"%@",x);
}];
//连接
[connect connect];

RACCommand

这是一个命令类,可以把事件如何处理,事件中的数据如何传递,包装到这个类中,他可以很方便的监控事件的执行过程,一般来说是在UI上的某些动作来触发这些事件,比如点击一个按钮,RACCommand的实例能够决定是否可以被执行,一般用于网络请求,监控请求过程。

@interface RACCommand: NSObject

//这是一个二阶信号,表示信号中包含子信号,一般使用flatten或switchToLatest来降阶
@property (nonatomic, strong, readonly) RACSignal<RACSignal<ValueType> *> *executionSignals;

//这个信号表示当前RACCommand是否正在执行,YES/NO
@property (nonatomic, strong, readonly) RACSignal<NSNumber *> *executing;

//这个信号表示RACCommand是否可用,如果初始化传NO或者allowsConcurrentExecution=NO,那个这个信号返回NO,否则为YES
@property (nonatomic, strong, readonly) RACSignal<NSNumber *> *enabled;

//表示RACCommand执行过程中产生的错误信号,当对错误信号进行处理的时候应该subscribeNext去订阅,而不是subscribeError。
@property (nonatomic, strong, readonly) RACSignal<NSError *> *errors;

//是否允许并发执行,默认为NO
@property (atomic, assign) BOOL allowsConcurrentExecution;

/**
 初始化
 @param signalBlock 返回信号的Block,在其内部进行保存,当进行execute的时候才会调用该Block
 @return self
 */
- (instancetype)initWithSignalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

/**
 初始化
 @param enabledSignal 是否可用
 @param signalBlock 返回信号的Block,在其内部进行保存,当进行execute的时候才会调用该Block
 @return self
 */
- (instancetype)initWithEnabled:(nullable RACSignal<NSNumber *> *)enabledSignal signalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

/**
 执行
 @param input 输出内容
 @return 组播连接对象的signal
 */
- (RACSignal<ValueType> *)execute:(nullable InputType)input;

@end

  1. 创建命令,初始化RACCommand对象,内部做的事情:
  1. signalBlock中创建RACSignal,用来做数据传递,如果不需要可以创建空信号[RACSignal empty]
  2. 执行命令execute,内部做的事情:
  //1.创建命令对象
  RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal *(id input) {
      //输出1,由execute传入
      NSLog(@"%@",input);
      //2.创建信号
      return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
          [subscriber sendNext:@(2)];
          // 注意:数据传递完,最好调用sendCompleted,这时命令才执行完毕。
          [subscriber sendCompleted];
          return nil;
      }];
  }];

  //获取信号传输的数据
  [command.executionSignals.switchToLatest subscribeNext:^(id x) {
      //输出2
      NSLog(@"%@",x);
  }];
  //这里用flatten跟switchToLatest也是一样的
  [[command.executionSignals flatten] subscribeNext:^(id  _Nullable x) {
      //输出2
      NSLog(@"%@",x);
  }];

  //监听命令是否执行完毕,初始化时会调用一次,用skip直接跳过。
  [[command.executing skip:1] subscribeNext:^(id x) {
      if ([x boolValue] == YES) {
          // 正在执行
          NSLog(@"正在执行");
      }else{
          // 执行完成
          NSLog(@"执行完成");
      }
  }];

  //3.执行命令
  RACSignal *connectSignal = [command execute:@1] ;
  [connectSignal subscribeNext:^(id  _Nullable x) {
      //输出2,connectSignal是connect.signal
      NSLog(@"%@",x);
  }];


RACChannel

这是一个通道类,可以理解为一个双向的连接,连接的两端都配有RACChannelTerminal(通道终端,继承自RACSignal,且又实现了RACSubscriber协议,所以它可以充当信号,又能发送信号),分别是leadingTerminalfollowingTerminal,只要其中任何一端输出信号,另一端都会有相同的信号输出。我们平时很少直接使用RACChannel,而是使用RACChannelTo

    RACChannelTerminal *followT = RACChannelTo(view,backgroundColor);
    [followT subscribeNext:^(id  _Nullable x) {
        //每点击一次就输出一次随机颜色
        NSLog(@"%@",x);
    }];
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]init];
    [tap.rac_gestureSignal subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
        //改变view.backgroundColor
        [followT sendNext:RandomColor];
    }];

    //将_textField.backgroundColor跟view.backgroundColor绑定
    RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);


常用宏

  //当textfield开始编辑时,关闭button响应
 RAC(_button,enabled) = [[self rac_signalForSelector:@selector(textFieldDidBeginEditing:) fromProtocol:@protocol(UITextFieldDelegate)] mapReplace:@NO];

[RACObserve(self.view, backgroundColor) subscribeNext:^(id  _Nullable x) {
    //x==新背景颜色
    NSLog(@"%@",x);
}];

//将_textField.backgroundColor跟view.backgroundColor绑定
  RACChannelTo(button,backgroundColor) = RACChannelTo(view,backgroundColor);

RACTuple *tuple = RACTuplePack(@1,@2,@"3");

 //传入需要解析生成的变量名,从第一个开始解析
 RACTupleUnpack(NSNumber *num1,NSNumber *num2) = tuple;
 //输出1,2
 NSLog(@"%@,%@",num1,num2);

作者:大大盆子
链接:https://www.jianshu.com/p/8dbe8878d1c5
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇下一篇

猜你喜欢

热点阅读