在ReactiveCocoa中链接相关信号

时间:2013-04-03 20:09:17

标签: ios objective-c reactive-programming reactive-cocoa

在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 个答案:

答案 0 :(得分:48)

这是RACStreamRACSignal运营商真正开始派上用场的时候。在您的特定示例中,您可以使用-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:代替类似的效果(但更明确地表达意图)。