I'm working on a Form which consists of dynamically created Fields, and I'd like each Field to have a method that returns a RACSignal which sends a nextEvent each time the Field's value changes.
The payload of the nextEvent should include BOOL that indicates weather the Field is complete (which wraps up some validation logic along the way).
The best I can illustrate my intent so far is with the pseudo-code below:
// Inside Form.m
// Create an array of signals from all the fields in the form
@property(nonatomic) BOOL *formComplete;
-(void)setUpSignals {
NSMutableArray *fieldCompleteSignals = [NSMutableArray arrayWithCapacity:0];
for (Field *field in self.fields)
{
RACSignal *completeSignal = [field complete];
[fieldCompleteSignals addObject:completeSignal];
}
// ? S.O. Help here
[RACSignal combineLatest:self.fieldCompleteSignals reduce:^id {
self.formComplete = ?? // combined BOOL values, if any are NO, then returns NO- if all are YES, returns YES
return ??; // when all the BOOL values returned from the fields are YES, then the form is complete
}];
}
// Inside Field.m
@property(nonatomic, copy) NSString *value;
-(RACSignal *)fieldComplete
{
return [RACObserve(self, value) map:^id(id value) {
return @([self validateCurrentValue]);
}];
}
-(BOOL)validateCurrentValue
{
// snazzy validation logic here
return YES | NO;
}
This Form is dynamically created from an XML document, and I'd like to set up a pipeline that handles dynamically created RACSignals.
What I'd like to end up with is a stream of BOOL values, collected from each Field, and reduced to a single formIsComplete BOOL- I'm wondering if I'm on the right track to setting up this pipeline if there's a better way (or other examples) of handling this?
Fo your first question, you can use map
along with RACTuple
:
@property (assign, nonatomic) BOOL formComplete;
- (void)setUpSignals {
NSMutableArray *fieldCompleteSignals =
[NSMutableArray arrayWithCapacity:self.fields.count];
for (Field *field in self.fields) {
RACSignal *completeSignal = [field complete];
[fieldCompleteSignals addObject:completeSignal];
}
RAC(self, formComplete) =
[[RACSignal
combineLatest:self.fieldCompleteSignals]
map:^id (RACTuple *allValues) {
return @([allValues.rac_sequence all:^BOOL(id value) {
return [value boolValue];
}]);
}];
}
RACTuple
is an ordered collection and conforms to NSFastEnumeration
protocol (To learn more about RACTuple
see RACTuple reference).
For your second question, yes boxing primitive types is appropriate. Say that you would like to enable some button only when some other BOOL
is YES
, you can do it like this:
RAC(self.button, enabled) = RACObserve(self, formComplete);