我正在创建一个音乐播放器,它可以响应用户点击某个表格行,或者使用 Remote 上的上一个/下一个按钮。
要获取表示第一种情况当前播放轨道索引的信号,我会将其设为点击行的函数,例如:
RACSignal *didSelectS = [[self rac_signalForSelector:@selector(tableView:didSelectRowAtIndexPath:)] map:...
后一种情况,我会使用 scanWithStart:reduce: ,根据用户按下的按钮传入 +1/-1 并根据此返回新的绝对索引,例如。
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);
}];
我的问题是,如何将这两者结合起来?一种解决方案是将这些值包装在一个对象中,以便我在 scanWithStart:reduce: 中可以区分绝对值或相对值,例如:
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;
}
}
但是 isKindOfClass 和包装的对象感觉不太对......
最佳答案
您可以映射到 block 而不是值,
NSNumber * (^nextTrack)(NSNumber *) = ^(NSNumber *currentTrack) {
return @(currentTrack.integerValue + 1);
};
NSNumber * (^previousTrack)(NSNumber *) = ^(NSNumber *currentTrack) {
return @(currentTrack.integerValue - 1);
};
现在将 -mapReplace:
替换为 @1
/@-1
。
对于轨道选择,-map:
(或此处的-reduceEach:
)向忽略轨道参数并返回捕获轨道的 block 发出信号:
reduceEach:^(id tableView, NSIndexPath *indexPath) {
NSInteger newTrack = indexPath.row;
return ^(NSNumber *currentTrack) {
return @(newTrack);
};
}
现在,可以合并和扫描这些:
RACSignal *currentIndexSignal = [[RACSignal
merge:@[didSelectS, prevS, nextS]]
scanWithStart:@0 reduce:^(NSNumber *running, NSNumber * (^trackChanger)(NSNumber *)) {
return trackChanger(running);
}];
关于reactive-cocoa - 合并不同类型的信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23479141/