ReactiveCocoa - 如果第一个信号没有值,则订阅第二个信号

时间:2015-02-11 08:11:19

标签: reactive-cocoa

想象一下,我有两个信号:一个便宜的信号和一个昂贵的信号:

RACSignal *localSignal;      // Cheap signal. Sends object without network request 
                             // if possible, otherwise completes immediately. 

RACSingal *networkSignal;    // Expensive one. Always sends data, 
                             // but requires expensive network operation.

现在我想创建一个信号,该信号从第一个信号发送值(如果有的话),或者订阅第二个信号并从那个信号发送数据。

以下解决方案几乎给了我想要的东西,但它总是订阅第二个昂贵的信号,即使从第一个信号中取出一个值,也忽略了第二个信号的值。

[[localDataSignal concat:networkDataSignal] take:1];

有没有办法有效地解决问题?

3 个答案:

答案 0 :(得分:3)

我刚刚发现了什么问题。本地信号使用与创建和调用它相同的线程:

RACSignal *localSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
    NSLog(@"Perfoming local operation");
    [subscriber sendNext:@"local value"];
    [subscriber sendCompleted];
    return nil;
}];  

当我看到问题(我不确定为100%)时:1甚至没有机会处理连接的网络信号。但是如果我在不同于主线程调度程序的情况下调度本地信号,则取:1按预期工作 - 它在获得第一个值后打破链。

简单来说,这个代码段就可以了:

[[[localSignal deliverOn:[RACScheduler scheduler]] concat:networkSignal] take:1]

它给了我我想要的东西:本地信号的值,如果有的话,或订阅网络信号并给我它的价值。如果本地信号发送值,网络信号永远不会被订阅。

经验法则是检查信号工作的线程,然后采取:1应按预期工作。

更新-deliveOnMainThread也为-take:提供了处理队列的机会。

答案 1 :(得分:1)

您可以使用:

- (RACSignal *)catchTo:(RACSignal *)signal;

像这样:

[[localSignal catchTo:networkSignal] subscribeNext:^(id x) {
    // If localSignal sends error, networkSignal will be subscribed.
}];

答案 2 :(得分:1)

它有点难看,但在网络信号之前,连接一个有延迟的空信号。我还没试过这个,但它应该引入所需的异步,以便在take发送值的情况下允许networkSignal阻止localSignal订阅。这种方法不会影响localSignal的值的传递。

[[RACSignal concat:@[
    localSignal,
    [[RACSignal empty] deliverOn:RACScheduler.mainThreadScheduler],
    networkSignal
] take:1]

deliverOn:的替代方案,您可以考虑delay:,如果这样可以更容易理解此代码。