Используя combLatest, есть ли способ узнать, какой сигнал вызвал событие?

Как указано в заголовке, есть ли способ выполнить следующее:

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

Итак, в блоке subscribeNext я в настоящее время не знаю, какой сигнал сработал.

Проблема, которую я пытаюсь решить, связана с генерацией сигналов для селекторов (используя rac_signalForSelector), и я хочу получать уведомления при запуске любого из этих методов. Я хочу объединить события вместе, но мне не нужно последнее значение ни для одного из них, кроме метода, который был фактически вызван.

e.g.

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?
}];

person Patrick    schedule 05.01.2016    source источник
comment
Не использую combineLatest. Тем не менее, я чувствую сильную атмосферу xyproblem.info. Какую большую проблему вы пытаетесь решить?   -  person Ian Henry    schedule 05.01.2016
comment
Отредактировано, чтобы включить большую картину, спасибо.   -  person Patrick    schedule 06.01.2016


Ответы (2)


Предполагая, что signal1 и signal2 в вашем примере отправляют значения одного и того же типа, и вы хотите сделать то же самое со значениями каждого сигнала, вы можете использовать merge: вместо combineLatest:, чтобы просто получить сигнал значений, которые срабатывает каждый:

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

Если вы хотите относиться к ним по-разному, тогда вообще не нужно использовать combineLatest: или merge: — вы можете просто подписаться на каждый отдельно.

Обратите внимание, что одно различие между merge: и combineLatest: заключается в том, что с merge: ваш блок будет вызываться, как только будет вызван первый метод - он не будет ждать, пока каждый метод будет вызван хотя бы один раз, прежде чем он начнет срабатывать, как combineLatest: . Если такое поведение желательно, его можно добиться с помощью оператора then:.


В случае, если вам нужно необходимо знать не только аргумент метода "последний вызванный", но также аргументы последнего вызова других методов, и вам нужно дождаться, пока каждый метод будет вызван хотя бы один раз... одна вещь, которую вы можете сделать, это сопоставить каждый сигнал с кортежем (id whateverTheyActuallySent, NSUInteger sharedMonotonicallyIncreasingIdentifier), затем объединить эти сигналы, а затем отсортировать их на основе этого идентификатор.

Это было бы... неэлегантно, но только в очень странной ситуации это оправдано, и если вы действительно считаете, что это лучший подход, может быть хорошо уменьшить масштаб еще на один уровень, чтобы посмотреть, можно ли изменить что-то еще, чтобы вы не т должен сделать это в конце концов.

person Ian Henry    schedule 06.01.2016
comment
Спасибо за отличный ответ, Ян, слияние было определенно тем, что мне было нужно. Я думал о вашем решении использовать кортеж, но я согласен, что это было бы неэлегантно. Благодаря некоторому дополнительному отображению на signal1 и signal2 я смог чисто затем использовать слияние. Ваше здоровье. - person Patrick; 06.01.2016

Как упомянул Ян в своем ответе, вы, вероятно, захотите использовать merge вместо combineLatest.

Поскольку вам не нужны значения из rac_signalForSelector, вы можете использовать оператор mapReplace, чтобы различать method1 и method2:

  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
    }
  }];

Я нашел этот подход полезным для обработки «противоположных» событий, таких как rac_signalForControlEvents с параметрами UIControlEventTouchDownInside и UIControlEventTouchUpInside.

person Michał Ciuba    schedule 06.01.2016