Reputation: 1714
I'm creating a music player that will either respond to the user tapping a certain table row, or using the prev/next buttons on his remote.
To get a signal representing the index of the current playing track for the first case, I'd make it a function of the tapped row, eg:
RACSignal *didSelectS = [[self rac_signalForSelector:@selector(tableView:didSelectRowAtIndexPath:)] map:...
The latter case, I'd use a scanWithStart:reduce: where I'd pass in +1/-1 depending on which button the user presses and return a new absolute index according to this, eg.
RACSignal *prevS = [[remoteControlSignal filter:^BOOL(UIEvent *event) {
return event.subtype == UIEventSubtypeRemoteControlPreviousTrack;
}] mapReplace:@-1];
RACSignal *nextS = [... mapReplace:@1];
RACSignal *trackIdxS = [RACSignal merge:@[nextS, prevS]]
scanWithStart:@0
reduce:^id(NSNumber *running, NSNumber *next) {
return @(running.integerValue + next.integerValue);
}];
My problem is, how do I combine these two? One solution would be to wrap the values in an object, so that I in my scanWithStart:reduce: could distinguish between an absolute or a relative value, eg:
RACSignal *currentIndexSignal = [[RACSignal merge:@[didSelectS, prevS, nextS] scanWithStart:@0 reduce:^id(NSNumber *running, id next){
if ([next isKindOfClass:[PrevNextValueWrapper class]]){
// next is a wrapped relative value, eg -1/+1
return @(running.integerValue + next.wrappedNumber.integerValue)
} else {
// next is an absolute value
return next;
}
}
But the isKindOfClass and the wrapped object just doesn't feel right ...
Upvotes: 2
Views: 467
Reputation: 6489
You could map to blocks instead of values,
NSNumber * (^nextTrack)(NSNumber *) = ^(NSNumber *currentTrack) {
return @(currentTrack.integerValue + 1);
};
NSNumber * (^previousTrack)(NSNumber *) = ^(NSNumber *currentTrack) {
return @(currentTrack.integerValue - 1);
};
Now -mapReplace:
to those instead of @1
/@-1
.
For track selection, -map:
(or here -reduceEach:
) the signal to a block that ignores the track argument and returns the captured track:
reduceEach:^(id tableView, NSIndexPath *indexPath) {
NSInteger newTrack = indexPath.row;
return ^(NSNumber *currentTrack) {
return @(newTrack);
};
}
Now, these can be merged and scanned:
RACSignal *currentIndexSignal = [[RACSignal
merge:@[didSelectS, prevS, nextS]]
scanWithStart:@0 reduce:^(NSNumber *running, NSNumber * (^trackChanger)(NSNumber *)) {
return trackChanger(running);
}];
Upvotes: 5