Search code examples
iosobjective-creactive-cocoa

How to prevent a signal to send a next event before subsequent asynchronous calls are completed?


I am willing to prevent a RAC signal to send a next event message before some subsequents calls are completed.

Here is an example of how i have proceed so far:

- (RACSignal *) fetchNearbyDatasForLocation: (CLLocationCoordinate2D)coordinate {

    RACSignal* finalSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
        [subscriber sendNext:self.rawDatas];
        [subscriber sendCompleted];
        return nil;
    }];

    return [[[self.apiClient fetchNearbyDatasforLocation:coordinate]            
             flattenMap:^RACStream *(NSArray* datas) {

                    NSMutableArray* signals = [[NSMutableArray alloc] init];
                    self.rawDatas = datas;

                    for (SNPDataModel* data in datas) {
                        RACSignal* fetchExtraDataSignal = [self.apiClient fetchExtraDataInfoForData:data];
                        [signals addObject:fetchExtraDataSignal];
                        RAC(data, extraData) = fetchExtraDataSignal;

                    }

                    // will send a next message when all asynchronous call are completed 
                    RACSignal* completedSignal = [RACSignal combineLatest:signals];

                return completedSignal;
            }]
            flattenMap:^RACStream *(RACTuple* value) {

                return finalSignal;

            }];
} 

Few explanation about my code here: I am trying to fetch an array of datas and send a signal with the same array when all fetchExtraDataSignal signals have completed (so the array should now have the extra data content at that time). Is there a better reactive way to achieve this? I would like to not rely on the property datas if that's possible.


Solution

  • Although I don't have self-confidence in understanding what you are meaning, I recommend using "map", instead of the combination of "createSignal" and "flattenMap".

    Like this.

    - (RACSignal *) fetchNearbyDatasForLocation: (CLLocationCoordinate2D)coordinate {
        return [[self.apiClient fetchNearbyDatasforLocation:coordinate]
            flattenMap:^RACStream *(NSArray* datas)
        {
            /* ... */;
            return [[RACSignal combineLatest:signals]
                map:^(RACTuple *unused) { return datas; }]];
        }];
    }
    

    And I strongly recommend don't use any mutable fields to communicate data among event handlers. That causes results of these become unpredictable when multiple signals are simultaneously working.