RxSwift subscribe sequence - swift

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.

Related

Subscribe cancels the subject when the source publisher completes

I have a function which receives a Publisher and creates a PassthroughSubject that is used to both:
subscribe to the source publisher
send values manually
E.g.:
class Adapter<T>{
let innerSubject=PassThroughSubject<T,Never>()
let scope = Scope() // custom type, Array<AnyCancellable>
func init(_ source:Publisher<T,Never>){
source.register(innerSubject).in(scope)
innerSubject.sink(receiveValue:{debugPrint($0)}).in(scope)
}
func adapt(_ T val){
innerSubject.send(val)
}
}
fn usage(){
let adapter=Adapter(Empty()) // change to Empty(completeImmediately:false) to fix
adapter.adapt(42) // should print 42,
}
The inner subject seems to be cancelled because Empty calls complete.
I would expect the inner subject's subscription to be cancelled, not the subject itself. In .Net at least that's the behaviour - am I missing something? Do I need to wrap this in a broadcasting subject? I thought that Publishers could receive multiple Receivers and multicast to each?
I would expect the inner subject's subscription to be cancelled, not the subject itself. In .Net at least that's the behaviour - am I missing something?
Just like with Observables, when a Publisher emits a completed event, it will not emit any more events. A Subject is a kind of Publisher. The behavior is exactly the same as in .Net so I can only assume you are missing something.
I thought that Publishers could receive multiple Receivers and multicast to each?
Yes they can. But they send the exact same values to each receiver, including the completion event. However, again just like with Observables and Rx Subjects, once it emits a completion event, it cannot emit anything else.

Correct way to restart observable interval in RxSwift

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).

Does a read only BehaviorSubject interface exist in RX and if not, is it a bad idea to make one?

Implementations of rx provide BehaviorSubject<T> and Variable<T> as mechanisms for modeling properties that change over time (a useful replacement for C# INotifyPropertyChanged).
Generally these are exposed as Observable<T> but it would be more useful to expose properties as something like:
class ObservableValue<T> : Observable<T>{
var currentValue:T { get }
}
This can be created along these lines in swift:
class ObservableValue<Element> : ObservableType {
typealias E = Element
private let subject:BehaviorSubject<E>
var currentValue:E {
get {
return try! subject.value()
}
}
init(subject:BehaviorSubject<E>) {
self.subject = subject
}
func subscribe<O: ObserverType where O.E == E>(observer: O) -> Disposable {
return self.subject.subscribe(observer)
}
}
Does this already exist? and if not is it because it's against the aims of Rx?
The only way around it is to expose a separate currentValue or write consumers that assume the concrete implementation behind the exposed Observable is a BehaviourSubject or somewhere in the chain a replay() has occured e.g. the following snippet doesn't make it explicit that as soon as I subscribe I will get a value:
class MyViewModel {
// 'I will notify you of changes perhaps including my current value'
myProperty:Observable<String>
}
so code has to be written as if its 'asynchronous' with an underlying assumption it will act in an almost synchronous manner rather than:
class MyViewModel {
// 'I have a current value and will notify you of changes going forward'
myProperty:ObservableValue<String>
}
Having thought it over and discussed it a bit more presumably the reason it doesn't (and perhaps shouldn't exist) is that it's an introduction of imperatively accessed state.
Other mechanisms of maintaining state (such as scan) do so within the confines of chained observables rather than as 'dead-end' direct calls such as 'give me the value right now'.
Perhaps it would have it's place in a hybrid reactive/imperative approach but it may just hinder full embracement of the reactive style.
It's analogous to using promises or tasks in half of the code then reverting to synchronous blocking code in other parts.
In most cases what people do is create a standard view model that exposes properties via INotifyPropertyChanged. This allows UI elements to bind to them and receive property change events and keep the UI in sync.
Then if you want an IObservable for said property you take advantage of standard Rx operators that turn events into IObservable. You can google this to find lots of different implementations. You would generally create and consume these observables from something that is observing the view model rather than expose them on the view model directly.

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.