2017-08-16 30 views
0

我有一种情况,我想将事件从一个特定的原点信号分成两个信号,一个立即发射事件,另一个发射事件延迟3秒。其他原始事件总是立即发出新事件。 但是,如果在事件发生之前新事件到达原点信号,则应放弃延迟事件。如何通过使用ReactiveCocoa来满足这种情况

像这样 enter image description here

我映射每个原点信号CS1(对于立即发出的事件),并且原点信号的特定事件过滤到CS2(用于延迟发出的事件)enter image description here enter image description here

然后我合并CS1CS2CS3,不会丢弃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]]; 

回答

1

一个备注无关的实际问题:filter应该返回一个布尔值是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来演示解决方案。

+0

非常感谢。这是非常令人印象深刻的答案。我找到了另一个解决方案(CS2返回信号,然后switchToLatest),但它只是丢弃信号,映射块总是处理。你的答案更加优雅和优化。 – Tepmnthar

+0

似乎CS2永远不会触发@MeXx – Tepmnthar

+0

不是吗?我构建了一个小样本应用程序,通过按钮在'origin'上发送值,并且在该示例中工作。也许你可以展示你的用例的更大图片? – MeXx