Подтвердить что ты не робот

Цепочка зависимых сигналов в 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?

4b9b3361

Ответ 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: вместо аналогичного эффекта (но для более четкого выражения намерения).