在ReactiveCocoa中链接相关信号

Ser*_*nov 32 objective-c reactive-programming ios 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
    }];
}];
Run Code Online (Sandbox Code Playgroud)

这种不断增加的嵌套看起来并不比文档中给出的非反应性示例好多少:

[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];
}];
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?在ReactiveCocoa中是否有更好的链接依赖工作模式?

Jus*_*ers 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
    }];
Run Code Online (Sandbox Code Playgroud)

如果您不需要任何步骤的结果,您可以使用-sequenceMany:-sequenceNext:代替类似的效果(但更清楚地表达意图).