如何使用 ReactiveCocoa 来满足这种情况
How to satisfy this situation by using ReactiveCocoa
我有一种情况,我想将来自特定源信号的事件分成两个信号,一个立即发出事件,另一个延迟 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]];
一个与实际问题无关的评论:filter
应该 return 一个布尔值,如果应该发送元素,则为 YES
,如果应该发送元素,则为 NO
过滤掉了。
实际问题:
问题的解决方法是使用takeUntil
。但是,如果您直接将 takeUntil
应用于 CS2,则一旦事件到达 CS1,CS2 将作为一个整体被取消。
解决方案是使用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 来演示解决方案。
我有一种情况,我想将来自特定源信号的事件分成两个信号,一个立即发出事件,另一个延迟 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]];
一个与实际问题无关的评论:filter
应该 return 一个布尔值,如果应该发送元素,则为 YES
,如果应该发送元素,则为 NO
过滤掉了。
实际问题:
问题的解决方法是使用takeUntil
。但是,如果您直接将 takeUntil
应用于 CS2,则一旦事件到达 CS1,CS2 将作为一个整体被取消。
解决方案是使用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 来演示解决方案。