Correct way to restart observable interval in RxSwift - swift

In my OS X status bar app I'm using interval function to periodically call an external api and display the result:
Observable<Int>
.interval(120.0, scheduler: MainScheduler.instance)
.startWith(-1) // to start immediately
.flatMapLatest(makeRequest) // makeRequest is (dummy: Int) -> Observable<SummaryResponse?>
.subscribeNext(setSummary)
.addDisposableTo(disposeBag)
However, if user changes the preferences in the meantime, I would like to "restart" this interval and make a new call immediately to reflect the changes (without having to wait for the next call).
What's the best way to do this?
Store the observable as a property and set it to nil or call .dispose() on it (or both) and create a new observable ?
Set disposeBag to nil and create a new observable ?
Any other way?

What you're looking for is merge. You have two Observables, one of which is an interval and the other which represents preference changes. You want to merge those into one Observable with the elements from both, immediately as they come.
That would look like this:
// this should really come from somewhere else in your app
let preferencesChanged = PublishSubject<Void>()
// the `map` is so that the element type goes from `Int` to `Void`
// since the `merge` requires that the element types match
let timer = Observable<Int>.timer(0, period: 3, scheduler: MainScheduler.instance).map { _ in () }
Observable.of(timer, preferencesChanged)
.merge()
.flatMapLatest(makeRequest)
.subscribeNext(setSummary)
.addDisposableTo(disposeBag)
Also notice how I'm using timer instead of interval, since it allows us to specify when to fire for the first time, as well as the period for subsequent firings. That way, you don't need a startWith. However, both ways work. It's a matter of preference.
One more thing to note. This is outside of the scope of your question (and maybe you kept it simple for the sake of the question) but instead of subscribeNext(setSummary), you should consider keeping the result as an Observable and instead bindTo or drive the UI or DB (or whatever "summary" is).

Related

RxSwift subscribe sequence

I have two subscribers for a BehaviorRelay observable type named profileUpdates.
Publishing my data through,
Observables.shared.profileUpdates.accept(data)
Subscribing in two points in code (Suppose A and B) through,
Observables.shared.profileUpdates.subscribe(onNext: { } )
Now, can I define the sequence I would be able to get the subscribed data or it is strictly dependant on the library?
For example, in point A after point B, or vice versa.
There is no documented contract that guarantees the order that subscribes will be called in. They will be called sequentially, but the order is undefined.
It would be best to use the do operator for this:
profileUpdates
.do(onNext: { value in
// perform side effect
})
.subscribe(onNext: { value in
// perform other side effect
})
.disposed(by: disposeBag)
However, excessive use of the do operator (and Relays for that matter) are a code smell and imply you are still thinking imperatively.

PassthroughSubject with no initial value

I want to create a Swift Combine publisher that transmits a value and always gives the latest value when someone subscribes to it. However I want to only transmit a value once I have one - from an asynchronous call that’s triggered by the first subscriber. Pass through subject doesn’t work for that need, is there any good way to accomplish this?
You can use CurrentValueSubject for this:
let subject = CurrentValueSubject<T, E>(someValue)
func whatever() -> AnyPublisher<T, E> {
return subject.dropFirst().eraseToAnyPublisher()
}

Concatenating two observable sequences that both have subscribeOn. How do I ensure my observable runs on a thread?

When it comes to enforcing that a certain piece of Observable.create code runs in a specific thread (i.e. background thread), i worry that using the subscribeOn operator might not work because there are times that I might chain this observable sequence to another observable sequence that runs on a main thread (using observeOn).
Example
The situation is that I have an Observable sequence running on the main thread (i.e. an alert box asking the user for input, as to whether perform the network call or not).
Would it be better to ensure that this Observable.create code runs in the background thread by having something like:
Observable<String>.empty()
.observeOn(ConcurrentMainScheduler(queue: background.queue))
.concat(myObservableNetworkCall)
Why not just use subscribeOn?
The problem is if I had used subscribeOn (second) and the previous observable (the alert controller) was set to run on the background thread using subscribeOn (first), then the second subscribeOn operator would not work since the first call is closer to the source observable:
If you specify multiple subscribeOn() operators, the one closes to the source (the left-most), will be the one used.
Thomas Nield on RxJava's subscribeOn and observeOn operators (February 2016)
That may be the behavior for RxJava, but I am not sure for Swift. Reactivex.io simply says that we should not call subscribeOn multiple times.
I tend to wrap operations into Observable<Void>s and they need to be run on different threads... That is why I am asking for how to ensure an Observable code run in the thread I specified it to. subscribeOn wouldn't work because I can concatenate the observable.
I want the thread it should run in to be encapsulated in my Observable definition, not higher up in the chain.
Is the best practice to do the following:
Start with an Observable.empty using the data type I wish to use.
Use observeOn to force the thread that I want it to run in.
Concatenate it with the actual Observable that I want to use.
Edit
I have read the subscribeOn and observeOn documentation on reactivex.io.
I'm familiar with how to switch between threads using subscribeOn and observeOn.
What I'm specifically concerned about is the complication of using subscribeOn when concatenating or combining observable sequences.
The problem is, the observables need to run specifically on one thread, AND they don't know where and who they'll be concatenated with. Since I know exactly which thread they should run on, I'd prefer to encapsulate the scheduler definition within the observable's definition instead of when I'm chaining a sequence.
In the function declaration it is better not to specify on which thread the function is to be called.
For instance:
func myObservableNetworkCall() -> Observable<String> {
return Observable<String>.create { observer in
// your network code here
return Disposables.create {
// Your dispose
}
}
}
func otherObservableNetworkCall(s: String) -> Observable<String> {
return Observable<String>.create { observer in
// your network code here
return Disposables.create {
// Your dispose
}
}
}
And then switch between Schedulers:
myObservableNetworkCall()
.observeOn(ConcurrentMainScheduler(queue: background.queue)) // .background thread, network request, mapping, etc...
.flatMap { string in
otherObservableNetworkCall(s: string)
}
.observeOn(MainScheduler.instance) // switch to MainScheduler, UI updates
.subscribe(onNext:{ string in
// do something
})

How to pass a variable along when chaining observables?

I'm pretty new to RxJava, and whenever I have a case where I need to pass return data from one observable down the chain until a call to 'subscribe' - I have trouble understanding how to do it the 'Reactive' way without any patches...
For example:
Observable<GameObject> obs1 = func1();
Observable<GameObject> obs2 = func2();
Observable<GameObject> obs3 = func3();
Observable<GameObject> obs3 = func4();
I would like to emit obs1 and obs2, get their result, then emit obs3 then obs4 and then end the chain with subscribe while having the access to the results of obs1,obs2,obs3 and obs4.
The order of the calls is important, I need obs1 and obs2 to complete before obs3 is executed.
same goes for obs3 and obs4 - I need obs3 to complete before obs4 is executed.
How can I do that?
I know it's a pretty digested question - but this is one of the most problematic issues when a developer starts to know rxJava.
Thanks.
You can do it using Observable.zip and simple Observable.map/Observable.flatMap:
Observable.zip(obs1, obs2, (res1, res2) -> {
// do stuff with res1, res2
return obs3.flatMap(res3 -> {
// do stuff with res1, res2, res3
return obs4.flatMap(res4 -> {
// do stuff with res1, res2, res3, res4
return result;
});
});
});
This will force your scheduling requirements:
observables 1 and 2
observable 3
observable 4
Since I had the same kind of doubts in mind a while ago, the question seams to be related to how Observables really work.
Let's say you created obs1 and obs2 using something like:
Observable<GameObject> obs1 = Observable.create(...)
Observable<GameObject> obs2 = Observable.create(...)
You have 2 independent and disconnected streams. That's what you want when each of them are supposed to do something like a network request or some intensive background processing, which can take some time.
Now, let's say you want to watch for both results and emit a single value out of them when they get ready (you didn't say explicitly that, but it's gonna help you understand how it works). In this case, you can use the zipWith operator, which takes a pair of items, the first item from the first Observable and the second item from the second Observable, combine them into a single item, and emit it to the next one in the chain that may be interested on it. zipWith is called from an Observable, and expects another Observable as param to be zipped with. It also expects a custom function that knows how to zip the 2 source items and create a new one out of them.
Observable<CustomObject> obs3 = obs1.zipWith(obs2, new Func2<GameObject, GameObject, CustomObject>() {
#Override
public CustomObject call(GameObject firstItem, GameObject secondItem) {
return new CustomObject(firstItem, secondItem);
}
});
In this case, the CustomObject is just a pojo. But it could be another long running task, or whatever you need to do with the results from the first two Observable items.
If you want to wait for (or, to observe!) the results coming from obs3 you can plug another Observable at the end, which is supposed to perform another piece of processing.
Observable<FinalResult> obs4 = obs3.map(new Func1<CustomObject, FinalResult>() {
#Override
public FinalResult call(CustomObject customObject) {
return new FinalResult(customObject);
}
});
The map operator transforms (or maps) one object into another. So you could perform another piece of processing, or any data manipulation, and return a result out of it. Or your FinalResult might be a regular class, like CustomObject, just holding references to the other GameObjects.. you name it.
Depending how you created your Observables, they may not have started to emit any items yet. Until now you were just creating and plugging the data pipes. In order to trigger the first task and make items flow in the stream you need to subscribe to it.
obs4.subscribe();
Wrapping up, you don't really have one single variable passing along the whole chain. You actually create an item in the first Observable, which notifies the second one when it gets ready, and so on. Additionally, each step (observable) transforms the data somehow. So, you have a chain of transformations.
RxJava follows a functional approach, applying high order functions (map, zip, filter, reduce) to your data. It's crucial to have this clear. Also, the data is always immutable: you don't really change an Observable, or change your own objects. It creates new instances of them, and the old objects will eventually be garbage collected. So obs1.zip(...) doesn't change obs1, it creates a new Observable instance, and you can assign it to a variable.
You can also drop the variable assignments (obs1, obs2, obs3 etc) and just chain all methods together. Everything is strongly typed, so the compiler will not let you plug Observables that don't match each other (output of one should match input of the next).
I hope it gives you some thoughts!

What is this ScalaRX code doing?

So I'm pretty new to both Scala and RX. The guy who knew the most, and who actually wrote this code, just left, and I'm not sure what's going on. This construct is all over his code and I'm not really clear what its doing:
def foo(List[Long]) : Observable[Unit] =
Observable {
subscriber => {
do some stuff
subscriber.onNext()
subscriber.onCompleted()
}
I mostly get do some stuff, and the calls to subscriber. What I don't get is, where does subscriber come from? Does subscriber => { instantiate the subscriber? What does Observable { subscriber => { ... } } do/mean?
If you take a look at the Observable companion object documentation, you will see an apply method that takes a function of type (Subscriber[T]) ⇒ Unit. So, when you call Observable{withSomeLambda}, then this is the same as calling Observable.apply{withSomeLambda}
And, if you go all the way to the source code you will see that this is really returning
toScalaObservable(rx.Observable.create(f))
where f is the lambda that you passed in.
So, subscriber is just the parameter of the lambda. It is passed in by the caller of that function.
This code is creating a new Observable as described here.
Basically when a downstream component subscribes to this stream, this callback is called. In the callback we determine when we, as a data source, will call onNext(v: T) which is how we pass each element we are generating to them, and when we will call onCompleted() which is how we tell the subscriber that we are done sending data.
Once you have created an Observable you can start calling Observable operators, which will either result in another, compound Observable, or will result in a terminating condition which will end the process, and generally result in a final result for the flow (often a collection or aggregate value).
You don't use the List in your question, but normally if you wanted to make a reactive stream out of a list you would call Observable.from().
PS: I think this is RxJava code.