Imagine I have two signals: a cheap one and an expensive one:
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.
Now I want to create a signal, which sends value from the first signal, if any, or subscribe to the second one and sends data from that one.
The following solution almost gives me what I want, but it always subscribes to the second, expensive signal, even if a value from the first signal is taken, and the second signal's value is ignored.
[[localDataSignal concat:networkDataSignal] take:1];
Is there a way to solve the problem efficiently?
I've just found what was the problem. The local signal used the same thread where it was created and called on:
RACSignal *localSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
NSLog(@"Perfoming local operation");
[subscriber sendNext:@"local value"];
[subscriber sendCompleted];
return nil;
}];
As I see the problem (I am not sure for 100%) take:1 don't even had a chance to dispose the concatenated network signals. But if I schedule the local signal on a different than the main thread scheduler, then take:1 works as expected -- it breaks the chain, after it gets the first value.
In simple words this snippet works:
[[[localSignal deliverOn:[RACScheduler scheduler]] concat:networkSignal] take:1]
It gives me exactly what I wanted: local signal's value, if any, or subscribes to the network signal and gives me its value. In case the local signal sends value, the network signal never gets subscribed.
The rule of thumb is to check the thread the signal works on, then take:1 should do its work as expected.
Update: -deliveOnMainThread
also gives -take:
the chance to dispose the queue.