Reputation: 2929
This is a similar question to an earlier question that asked about observing every item in a RACSequence — the correct answer was something like:
RACSignal *valid = [[RACSignal combineLatest:
[self.viewModels map:^id(ViewModel *viewModel) {
return RACObserve(viewModel, state);
}]
]
map:^(RACTuple *states) {
return @([states.rac_sequence all:^BOOL(NSNumber *state) {
return state.unsignedIntegerValue == Completed;
}]);
}
];
My variation on this is that I'd like to also handle the case where ViewModel instances are added/removed from the sequence as well. I can do this by invalidating a RACDisposable stored in an instance variable or property, but it would be great to do this without adding any extra state. What's the right way to do this?
Upvotes: 1
Views: 108
Reputation: 2929
I found the answer in an older post by @justin-spahr-summers: https://stackoverflow.com/a/19711002/63580
Here is the version specific for my question above for posterity:
@weakify(self);
RACSignal *enabled = [[RACObserve(self, viewModels)
// Map _each_ array of view models to a signal determining whether the command
// should be enabled.
map:^(NSArray *viewModels) {
RACSequence *selectionSignals = [[viewModels.rac_sequence
map:^(ViewModel *viewModel) {
// RACObserve() implicitly retains `self`, so we need to avoid
// a retain cycle.
@strongify(self);
// Observe each view model's `state` property for changes.
return RACObserve(viewModel, state);
}]
// Ensure we always have one YES for the -and below.
startWith:[RACSignal return:@YES]];
// Sends YES whenever all of the view models are selected, NO otherwise.
return [[RACSignal
combineLatest:selectionSignals]
and];
}]
// Then, ensure that we only subscribe to the _latest_ signal returned from
// the block above (i.e., the observations from the latest `viewModels`).
switchToLatest];
Upvotes: 1