Search code examples
iosobjective-creactive-cocoa

Combine and reduce but wait for each signal to complete before subscribing to next one


I have 2 network signals and the first one needs to complete before the next one starts because I need to send an accessToken for the second request and I obtain that in the first request. Then I want to reduce the values from each step into a single object. I guess combineLatest:reduce: subscribes to both of them and has nothing to do with waiting completion of signal.

I have this right now:

- (RACSignal *)loginWithEmail:(NSString *)email password:(NSString *)password
{
    @weakify(self);
    RACSignal *authSignal = [[self requestTokensWithUsername:email password:password]  
        doNext:^(Authentication *auth) {
            @strongify(self);
            self.authentication = auth;  
        }];

    RACSignal *profileSignal = [self fetchProfile];
    NSArray *orderedSignals = @[ authSignal, profileSignal ];
    RACSignal *userSignal =
        [RACSignal combineLatest:orderedSignals
                          reduce:^id(Authentication *auth, Profile *profile) {
                              NSLog(@"combine: %@, %@", auth, profile);
                              return [User userWithAuth:auth profile:profile history:nil];
                          }];

    return [[[RACSignal concat:orderedSignals.rac_sequence] collect]
        flattenMap:^RACStream * (id value) {                
            return userSignal;
        }];
}

To ensure that they are done in order, I return a signal where I first concat: the signals, then collect them to send completed only when all of the signals complete, and flattenMap: to a combineLatest:reduce: to process latest result from each.

It works but I think there might be a more concise and better way to do this. How might I rewrite this part to make it more concise maybe?


Solution

  • FWIW, I simplified my code to this and somewhat happy with the results. I'm leaving it here for future reference.

    - (RACSignal *)loginWithEmail:(NSString *)email password:(NSString *)password
    {
        @weakify(self);
        RACSignal *authSignal = [[self requestTokensWithUsername:email password:password]  
            doNext:^(Authentication *auth) {
                @strongify(self);
                self.authentication = auth;  
            }];
    
        RACSignal *profileSignal = [self fetchProfile];
        RACSignal *historySignal = [self fetchHistory];
        RACSignal *balanceSignal = [self fetchBalanceDetails];
    
        NSArray *orderedSignals = @[ authSignal, balanceSignal, profileSignal, historySignal ];
    
        return [[[RACSignal concat:orderedSignals.rac_sequence]  
            collect]                                              
            map:^id(NSArray *parameters) {
    
                return [User userWithAuth:parameters[0]
                                  balance:parameters[1]
                                  profile:parameters[2]
                                  history:parameters[3]];
            }];
    }