Observe every item in RACSequence

2019-07-20 03:44发布

问题:

I have a method on ParentViewModel which returns an RACSequence of ViewModel objects like so:

- (RACSequence *) viewModels
{
    return [self.models.rac_sequence map:^id(Model *model) {
        return [[ViewModel alloc] initWithModel: model];
    }];
}

Each of the ViewModels has a state property on which is an enum and has 3 states: NotStarted, InProgress and Completed. When all the ViewModels in my sequence have the state Completed I know ParentViewModel is valid. I have a validSignal on the ParentViewModel which I want to derive the fact that is valid from the viewModels sequence. At the moment I have this code:

BOOL valid = [[self viewModels] all:^BOOL(ViewModel *vm) {
        return vm.state == Completed;
    }];

Which gives me an indicator if all ViewModels in the sequence are valid. How can I then turn this into a RACSignal which will update every time the state property on one of the ViewModels changes?

回答1:

You need first to turn state into a RACSignal, and then everything is easy from that point.

The final code will be something like the following:

RACSignal *valid = [[RACSignal combineLatest:
                     [[self viewModels] map:^id(ViewModel *viewModel) {
                       return RACAbleWithStart(viewModel, state);
                     }]
                    ]
                    map:^(RACTuple *states) {
                      return @([states.rac_sequence all:^BOOL(NSNumber *state) {
                        return state.unsignedIntegerValue == Completed;
                      }]);
                    }
                   ];

The first block maps each of your view models into a signal that observes the state property (with the starting value as first value of the signal).

combineLatest: will take a collection of RACSignals and will create a new signal that fires everytime one of the underlaying signals changes, and sends a RACTuple with the value of each signal.

That RACTuple is then converted into a RACSequence, and we can generate a value of @YES or @NO depending if all the values are Completed or not.

I think the result is the signal you were looking for.

(Disclaimer: I’m new to ReactiveCocoa, so there may be an easier way).