使用 combineLatest,有没有办法找出哪个信号发出了事件?

Using combineLatest, is there a way to find out which signal emitted the event?

如标题所述,有没有办法执行以下操作:

[[RACSignal combineLatest:@[signal1, signal2]] subscribNext:^id(RACTuple *signals) {
    // Did signal1 or signal2 emit an event?
}];

所以在 subscribeNext 块中,我目前不知道触发了哪个信号。

我试图解决的问题涉及为选择器生成信号(使用 rac_signalForSelector),我希望在这些方法中的任何一种被触发时得到通知。我想将事件合并在一起,但除了实际调用的方法之外,我不想要任何事件的最新值。

例如

RACSignal *signal1 = [self rac_signalForSelector@selector(method1:)];
RACSignal *signal2 = [self rac_signalForSelector@selector(method2:)];

[[RACSignal combineLatest:@[signal1, signal2]] subscribNext:^id(RACTuple *signals) {
    // Did signal1 or signal2 emit an event?
}];

假设您示例中的 signal1signal2 正在发送相同类型的值,并且您想对每个信号的值执行相同的操作,您可以使用 merge: 而不是 combineLatest: 以获得每个触发的值的信号:

[[RACSignal merge:@[signal1, signal2]] subscribeNext:^(NSObject *latestValue) {
    NSLog(@"%@", latestValue);
}];

如果您想区别对待它们,则根本不需要使用 combineLatest:merge: -- 您可以单独订阅每一个。

请注意 merge:combineLatest: 之间的一个区别是,对于 merge:,您的块将在第一个方法被调用时立即被调用——它不会等到每个方法在开始触发之前至少被调用一次,就像 combineLatest: 那样。如果需要这种行为,可以使用 then: 运算符来实现。


如果您不仅需要知道"most recently invoked"方法的参数而且参数从上次调用其他方法开始,您确实需要等到每个方法至少被调用一次……您可以做的一件事是将每个信号映射到 (id whateverTheyActuallySent, NSUInteger sharedMonotonicallyIncreasingIdentifier) 的元组中,然后组合 那些信号,然后根据该标识符对它们进行排序。

这将是...不雅观,但只有在非常奇怪的情况下才能保证这样做,如果您确实认为这是最好的方法,那么最好再缩小一个级别,看看是否可以更改其他内容这样您就不必这样做了。

正如 Ian 在他的回答中提到的,您可能想使用 merge 而不是 combineLatest

因为你不关心来自rac_signalForSelector的值,你可以使用mapReplace运算符来区分method1method2:

  RACSignal *signal1 = [[self rac_signalForSelector:@selector(method1:)] mapReplace:@YES];
  RACSignal *signal2 = [[self rac_signalForSelector:@selector(method2:)] mapReplace:@NO];

  [[RACSignal merge:@[signal1, signal2]] subscribeNext:^(NSNumber *latestValue) {
    if(latestValue.boolValue) {
      //first method was called
    }
  }];

我发现这种方法对于处理 "opposite" 事件很有用,例如带有参数 UIControlEventTouchDownInsideUIControlEventTouchUpInsiderac_signalForControlEvents