Цепные зависимые сигналы в ReactiveCocoa
В ReactiveCocoa, если мы объединяем несколько зависимых сигналов, мы должны использовать subscribeNext:
для следующего сигнала в цепочке, чтобы получить значение предыдущего сигнала (например, результат асинхронной операции). Итак, через некоторое время код превращается во что-то вроде этого (лишние детали опущены):
RACSignal *buttonClickSignal = [self.logIn rac_signalForControlEvents:UIControlEventTouchUpInside];
[buttonClickSignal subscribeNext:^(UIButton *sender) { // signal from a button click
// prepare data
RACSignal *loginSignal = [self logInWithUsername:username password:password]; // signal from the async network operation
[loginSignal subscribeNext:^void (NSDictionary *json) {
// do stuff with data received from the first network interaction, prepare some new data
RACSignal *playlistFetchSignal = [self fetchPlaylistForToken:token]; // another signal from the async network operation
[playlistFetchSignal subscribeNext:^(NSDictionary *json) {
// do more stuff with the returned data
}];
// etc
}];
}];
Эта постоянно увеличивающаяся вложенность выглядит не намного лучше, чем нереактивный пример, приведенный в документации:
[client logInWithSuccess:^{
[client loadCachedMessagesWithSuccess:^(NSArray *messages) {
[client fetchMessagesAfterMessage:messages.lastObject success:^(NSArray *nextMessages) {
NSLog(@"Fetched all messages.");
} failure:^(NSError *error) {
[self presentError:error];
}];
} failure:^(NSError *error) {
[self presentError:error];
}];
} failure:^(NSError *error) {
[self presentError:error];
}];
Я что-то пропустил? Есть ли лучшая схема связывания зависимых работ в ReactiveCocoa?
1 ответ
Это когда операторы RACStream и RACSignal действительно начинают пригодиться. В вашем конкретном примере вы можете использовать -flattenMap:
включить результаты в новые сигналы:
[[[buttonClickSignal
flattenMap:^(UIButton *sender) {
// prepare 'username' and 'password'
return [self logInWithUsername:username password:password];
}]
flattenMap:^(NSDictionary *json) {
// prepare 'token'
return [self fetchPlaylistForToken:token];
}]
subscribeNext:^(NSDictionary *json) {
// do stuff with the returned playlist data
}];
Если вам не нужны результаты какого-либо шага, вы можете использовать -sequenceMany:
или же -sequenceNext:
вместо этого для подобного эффекта (но для более ясного выражения намерения).