web-dev-qa-db-ja.com

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に依存する作業を連鎖させるより良いパターンはありますか?

32
Sergey Mikhanov

これは、 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:を使用して同様の効果を得ることができます(ただし、意図をより明確に表現するため)。

48