我有一种情况,我想将特定原点信号中的事件分成两个信号,一个立即发射事件,另一个发射事件延迟3秒。其余的原始事件总是立即发出新事件。 但是如果在发出延迟事件之前新事件到达原点信号,则应该丢弃延迟事件。
像这样的事情我将每个原始信号映射到 CS1(对于立即发射的事件),并将原始信号的特定事件过滤到 CS2(对于延迟发射的事件)。
然后我将 CS1 和 CS2 合并到 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]];
答案 0 :(得分:1)
与实际问题无关的一句话:filter
如果要发送元素,则应返回YES
的bool;如果要过滤掉该元素,则返回NO
。
对于实际问题:
问题的解决方案是使用takeUntil
。但是,如果您将takeUntil
直接应用于CS2,则CS2作为一个整体将在事件到达CS1时立即取消。
解决方案是使用flatMap
为延迟元素构建新的RACSignal
,然后在内部信号上使用takeUntil
。
为了清晰起见,我已将单个步骤拆分为多个临时信号(我还更改了map
和filter
所以我可以看到在尝试我的示例时发生的更好的事情,你应该很容易能够在那里使用你正确的功能):
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来演示解决方案。