ReactiveCocoa zip未按预期工作

时间:2015-09-03 01:23:38

标签: objective-c reactive-cocoa

我想用ReactiveCocoa处理数据流,我想要做的是,我想计算一段时间内数据流的平均值,然后使用该值减去平均值。流char看起来像这样

Data source -> extract value  ----> average---> zip
                              \              /
                               \------------/ 

所以你可以提取值信号产生平均信号,它也会发送到zip以结合平均信号的结果。

要演示的代码在这里

__block id<RACSubscriber> sourceSubscriber;
RACSignal *sourceSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    sourceSubscriber = subscriber;
    return nil;
}];

RACSignal *extractValueSignal = [sourceSignal map:^id(id value) {
    NSLog(@"extractValueSignal %@", value);
    return value;
}];

RACSignal *avgSignal = [extractValueSignal scanWithStart:[NSMutableArray array] reduce:^NSMutableArray *(NSMutableArray *array, id next) {
    NSLog(@"avgSignal %@", next);
    [array addObject:next];
    if (array.count > 5) {
        [array removeObjectsInRange:NSMakeRange(0, array.count - 5)];
    }
    return array;
}];

[[RACSignal zip:@[extractValueSignal, avgSignal] reduce:^id(NSNumber *value, NSNumber *avg) {
    NSLog(@"zip %@, %@", value, avg);
    return value;
}] subscribeNext:^(id x) {
    NSLog(@"output %@", x);
}];

[sourceSubscriber sendNext:@1];
[sourceSubscriber sendNext:@2];
[sourceSubscriber sendNext:@3];
[sourceSubscriber sendNext:@4];
[sourceSubscriber sendNext:@5];

输出

extractValueSignal 1
avgSignal 1
extractValueSignal 2
avgSignal 2
extractValueSignal 3
avgSignal 3
extractValueSignal 4
avgSignal 4
extractValueSignal 5
avgSignal 5

我在这里遇到的问题是从不调用zip块,也没有调用subscribeNext块。我想知道为什么它不起作用?我不应该在流量中有一个信号两次或什么?我应该使用类似tee的内容还是提取值信号的内容?

1 个答案:

答案 0 :(得分:0)

好的,回答我自己的问题,我注意到,如果你在createSignal块中添加一个NSLog

RACSignal *sourceSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"SUB %@", subscriber);
    sourceSubscriber = subscriber;
    return nil;
}];

你会注意到它会被调用两次,因为下游订阅了两次,所以订阅者被替换了,所以只有信号的一侧会被下一个事件发送。

要解决这个问题,只需创建多播连接

即可
RACMulticastConnection *conn = extractValueSignal.publish;
[conn connect];

然后你可以订阅

conn.signal

根据你的喜好,它只会调用一次。