akaralar
akaralar

Reputation: 1120

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?

Upvotes: 2

Views: 1644

Answers (2)

akaralar
akaralar

Reputation: 1120

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]];
        }];
}

Upvotes: 1

hybridcattt
hybridcattt

Reputation: 3041

Take look at - (RACSignal*)then:(RACSignal*(^)(void))block; I think it perfectly fits to your case. For example:

RACSignal* loginSignal = [[self authenticateWithUsername:username password:password] doNext:...];

RACSignal *resultSignal = [loginSignal then:^RACSignal* {
      return [self fetchProfile];
  }];
return resultSignal;

Upvotes: 2

Related Questions