想象一下,我有两个信号:一个便宜的信号和一个昂贵的信号:
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];
有没有办法有效地解决问题?
答案 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:
,如果这样可以更容易理解此代码。