如何使用 ReactiveCocoa 来满足这种情况

How to satisfy this situation by using ReactiveCocoa

我有一种情况,我想将来自特定源信号的事件分成两个信号,一个立即发出事件,另一个延迟 3 秒发出事件。其余的原始事件总是立即发出一个新事件。 但是,如果在延迟事件发出之前有新事件到达原始信号,则应丢弃延迟事件。

像这样

我将每个原始信号映射到 CS1(对于立即发出的事件),并将原始信号的特定事件过滤到 CS2(对于延迟发出的事件) )

然后我将CS1CS2合并成CS3,不会丢弃S2.

所以,我的问题是如何丢弃或取消 S2,以及如何在不使用额外临时变量的情况下使用 RAC 实现这种情况?

ReactiveCocoa 2.x 当前代码

RACSignal* origin = …    
RACSignal* CS1 = [origin map:^id _Nullable(id  _Nullable value) {
        return @(YES);
    }];
RACSignal* CS2 = [[[origin filter:^BOOL(id  _Nullable value) {
        return [RACSignal empty];
    }] delay:3] map:^id _Nullable(id  _Nullable value) {
        return @(NO);
    }];
RACSignal* CS3 = [RACSignal merge:@[CS1, CS2]];

一个与实际问题无关的评论:filter 应该 return 一个布尔值,如果应该发送元素,则为 YES,如果应该发送元素,则为 NO过滤掉了。

实际问题:

问题的解决方法是使用takeUntil。但是,如果您直接将 takeUntil 应用于 CS2,则一旦事件到达 CS1,CS2 将作为一个整体被取消。

解决方案是使用flatMap,为延迟元素构建一个新的RACSignal,然后在该内部信号上使用takeUntil

为了清楚起见,我将单个步骤拆分为多个临时信号(我还更改了 mapfilter 以便在尝试我的示例时可以更好地了解发生了什么,你应该可以很容易地在那里使用正确的功能):

RACSignal* CS1 = [self.origin map:^id _Nullable(NSNumber * _Nullable value) {
  return value;
}];

RACSignal *filtered = [self.origin filter:^BOOL(NSNumber * _Nullable value) {
  return (value.integerValue % 2) == 0;
}];

RACSignal *delayed = [filtered flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
  // Build a new signal that returns just this one value,
  // but delayed and only if no event arrives on CS1
  return [[[RACSignal return:value]
           delay:3]
          takeUntil:CS1];
}];

RACSignal* CS2 = [delayed map:^id _Nullable(NSNumber * _Nullable value) {
  return @(-value.integerValue);
}] ;


RACSignal* CS3 = [RACSignal merge:@[CS1, CS2]];

您可以轻松地将其折叠成两个信号

RACSignal *CS2 = [[[self.origin filter:^BOOL(NSNumber * _Nullable value) {
  return (value.integerValue % 2) == 0;
}] flattenMap:^__kindof RACSignal * _Nullable(id  _Nullable value) {
  // Build a new signal that returns just this one value,
  // but delayed and only if no event arrives on CS1 before
  return [[[RACSignal return:value]
           delay:3]
          takeUntil:CS1];
}] map:^id _Nullable(NSNumber * _Nullable value) {
  return @(-value.integerValue);
}];

我创建了 a sample project on github 来演示解决方案。