4

I'm building a feature where users of my app can find their Facebook friends and add them in the app. There are three steps which I have to do:

  1. Get the currently connected users
  2. Get the Facebook users
  3. Get the Application Users (this is dependent on step 2)

Once all of these complete I then need to combine/reduce the three resulting arrays into a final array.

I have created three functions that all return RACSignal

getUsersWithFacebookIds, getConnectedUsers, and getFacebookUsers

I'm not sure how to wire all of this using ReactiveCocoa.

enter image description here

Kyle Decot
  • 20,715
  • 39
  • 142
  • 263

1 Answers1

7

The Once All Are Done Do Something With All, can be achieve with:

[[RACSignal combineLatest:@[connectUsersSignal,facebookUsersSignal,applicationUsersSignal]] subscribeNext:^(RACTuple *users) {
    NSArray *connectedUsers = [users first];
    NSArray *facebookUsers = [users second];
    NSArray *applicationUsers = [users third];

}];

The other piece missing is how you make the applicationUsersSignal dependent on the facbookUsersSignal. Which could be done like this:

- (RACSignal *)applicationUsersSignalWithFacebookUsersSignal:(RACSignal *)fbSignal
{
    return [fbSignal flattenMap:^RACStream *(NSArray *facebookUsers) {
        return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            // Do what you have to do with the facebookUsers
            return nil;
        }];
    }];
}

Just to add a bit more to the answer. I am assuming those are cold signals, (signals that haven't started yet aka haven't been subscribed). So the idea of using combineLatest: is that you want to capture the point where each and every single signal as send at least one next, after that you subscribe to it so it can begin. Finally you can get their values from a RACTuple.


I re read your question and you want them to come all in a single Array:

[[[RACSignal combineLatest:@[connectUsersSignal,facebookUsersSignal,applicationUsersSignal]] map:^id(RACTuple *allArrays) {
    return [allArrays.rac_sequence foldLeftWithStart:[NSMutableArray array] reduce:^id(id accumulator, id value) {
        [accumulator addObjectsFromArray:value];
        return accumulator;
    }];
}] subscribeNext:^(NSArray *allUsers) {
    // Do Something
}];
Community
  • 1
  • 1
Rui Peres
  • 25,741
  • 9
  • 87
  • 137
  • It seems that the last code snippet can be simplified using `combineLatest:reduce` – Michał Ciuba Apr 17 '15 at 08:49
  • 1
    @MichałCiuba you would get 3 arrays in the `combineLatest:reduce:`, which is different from getting all 3 arrays flattened into one. – Rui Peres Apr 17 '15 at 09:43
  • 1
    @RuiAAPeres You can use `combineLatest:reduce:` to avoid the `allArrays.first`, `allArrays.second`, etc calls. But in this case, you can just get an `rac_sequence` from the tuple itself, and `map` remains the appropriate operation. – Ian Henry Apr 17 '15 at 22:24
  • @RuiAAPeres I meant something like this: https://gist.github.com/mciuba/9e8c6f31408a336b3749. I did a simple test and it seems to send the same array in `subscribeNext` block as with your code sample. Are there any differences I can't see? – Michał Ciuba Apr 18 '15 at 13:59
  • 1
    @MichałCiuba the problem with that solution, is that if I had a new Signal that returns an array, the `reduce` won't flat its elements. With a `fold` you don't have that issue. – Rui Peres Apr 18 '15 at 15:05