What are the differences between observable and subject.
When I define a observable type variable. It can emit onNext,onComplete,onDispose. However subject can do the same. When should I use observable and in what case should I use subject?
In order to understand the difference between them, we should mention that Observable is:
In ReactiveX an observer subscribes to an Observable. Then that
observer reacts to whatever item or sequence of items the Observable
emits. This pattern facilitates concurrent operations because it does
not need to block while waiting for the Observable to emit objects,
but instead it creates a sentry in the form of an observer that stands
ready to react appropriately at whatever future time the Observable
does so.
In other words, observable is data producer (responsible for posting notifications to be observed).
Actually, Subject is a special type of Observables (you still can subscribe to messages like any other observable):
A Subject is a sort of bridge or proxy that is available in some
implementations of ReactiveX that acts both as an observer and as an
Observable. Because it is an observer, it can subscribe to one or more
Observables, and because it is an Observable, it can pass through the
items it observes by reemitting them, and it can also emit new items.
but the thing is subject is a representation -as mentioned in the documentation- of both observable and observer, which means that subject might be data producer (responsible for posting notifications to be observed or data consumer (responsible for receiving notifications).
Also: For checking the types of the subjects, you might want to check: RxSwift Subject Types.
I think and as per I learned about this both topics, i can say that,
Observables
An Observable(fundamental part of Rx) is sequence with some special features. and most important feature is asynchronous. Observables produce some events(i.e onNext, onError, onCompleted), which called as emitting. Events contains some value(i.e Int, Bool, Array or custom type).
Subjects
Simple observable can only emits events, which can be subscribed. but what if we want to add some value on current observable(also called self observer). So simply i can say that something that works as an observable and also as a observer is called subjects.
You got a couple of answers explaining the difference between Observables and Subjects, but nobody has covered your second question...
When should I use observable and in what case should I use subject?
Here is an excellent, if complex, answer to that question:
http://davesexton.com/blog/post/To-Use-Subject-Or-Not-To-Use-Subject.aspx
The TL;DR is this. Use an Observable whenever possible, use a Subject whenever necessary.
You use a Subject whenever you need a hot observable and don't already have an observable to work with. RxCocoa, for example, uses Subjects extensively to create observables for you that are tied to particular UI elements. They are primarlly for bridging non-Rx code into Rx code and connecting producers to consumers where the latter must be created first for some reason.
Related
observable.subscribe(onNext: { _ in
somePrivateFunction()
})
What is the RxSwift way to test that when observable receives an event the somePrivateFunction actually gets called or not? Since the subscription and the function are in the same class I can't mock it.
You need to check if any logic is placed in a subscription that can block call of this function. If there is - it may be worth to extract it to a parameter (eg. filter) so that logic can be a part of stream itself.
I assume that observable (source) is injected/redirected from another component (if it's not, most probably it should be). To mock that signal you can use TestableObservable, you can read more here: http://adamborek.com/rxtests-rxactionsheet/
Last but not least - you need to identify what kind of action somePrivateFunction() does. If it's setting some external values - then you can test that outgoing connection from that function. If it sets some internal flags - you can test if value of that flag has changed.
On RxCocoa I was wondering why the PublishRelay doesn't have an asDriver() method like the BehaviorRelay ? Currently if I want to convert the publishRelay into a Driver, I have to specify what to return in case of error which seems weird given that the relays can't generate errors...
Those two versions of ...Relay are used to model different concepts:
BehaviorRelay represents State
PublishRelay represents Events
It makes sense to replay State, hence BehaviorRelay replays its latest value.
It makes less (no?) sense to replay Events, hence PublishRelay does not replay its latest value.
With this in mind, it makes sens for a BehaviorRelay to be transformable to Driver, as a driver drives the application using State. The sharing strategy for BehaviorRelay and Driver is to share side effects and replay the latest value while at least one observable is connected.
A PublishRelay is better represented by a Signal, so you probably could use a Signal to emit to. The sharing strategy in this case is will not replay the latest value, but still share the side effects while at least one observable is connected.
(I build this answer using this great comment from #freak4pc on RxSwift's repository)
If someone need a simple example:
publishRelay
.asDriver(onErrorDriveWith: Driver.empty())
.drive(onNext: { value in
})
.disposed(by: disposeBag)
I've created some very basic data bindings with variables between my VC and VM using RxSwift (which I've very new to), and am now perplexed as to how best communicate other UI actions from the VM that need additional data passed along with them.
Such as trigger popup alerts for error message passing, navigation controls, etc. as I want to send parameters along with them.
I've thought about using delegation again. But would it be inappropriate to mix bindings and delegation together in the same VM?
I'd like to abstract a pattern that can template to other MVVM areas of the app that would need to do the same thing for each VC/VM mix.
This can easily turn into an opinion based question, but if you want to stick with RxSwift, and I assume you do, the best way is to create subscriptions from the VC to VM. In essence, your VM would subscribe to a Variable, PublishSubject or similar in the VC and you would handle those where necessary.
For example of something like this using Strings as data:
let subject = PublishSubject<String>()
// As you can see the subject casts nicely, because it's an Observable subclass
let observable : Observable<String> = subject
observable
.subscribe(onNext: { text in
print(text)
})
.addDisposableTo(disposeBag)
// You can call onNext any time you want to emit a new item in the sequence
subject.onNext("Hey!")
subject.onNext("I'm back!")
You can have a look at more examples here:
http://swiftpearls.com/RxSwift-for-dummies-3-Subjects.html
If I write the following Dart code, how do I know which click handler happens first?
main() {
var button = new ButtonElement();
var stream = button.onClick.asBroadcastStream();
stream.listen(clickHandler1);
stream.listen(clickHandler2);
}
Let's say I'm in other code that doesn't know anything about the first two click handlers, but I register another one.
Can I know that the stream has two listeners?
Can I pause or cancel all other subscribers?
If I write button.onClick.asBroadcastStream() again elsewhere, does it point to the same stream as was used in main?
Can I say in one of the handlers to not pass event on to the other broadcast listener? Is that a consumer?
Let's say I'm in other code that doesn't know anything about the first
two click handlers, but I register another one.
Can I know that the stream has two listeners?
No, you can't. You could extend the stream class or wrap it and provide this functionality yourself, but it does not feel like a good design choice, because I don't think a listener should know about other listeners. What are you trying to do exactly? Perhaps there's a better way than letting listeners know about each other.
Can I pause or cancel all other subscribers?
You can cancel/pause/resume only the subscriber you are dealing with. Again, you probably shouldn't touch other listeners, but I guess you could wrap/extend the Stream class to have this behavior.
If I write button.onClick.asBroadcastStream() again elsewhere, does it point to the same stream as was used in main?
No, at least not at the current version of SDK. So, unfortunately, you need to store a reference to this broadcast stream somewhere, and refer to it, because calling asBroadcastStream() multiple times will not yield in the result you might expect. (Note: at least based on quick testing: http://d.pr/i/Ip0K although the documentation seems to indicate different, I have yet to test a bit more when I find the time).
Can I say in one of the handlers to not pass event on to the other broadcast listener?
Well, there's stopPropagation() in the HTML land which means that the event won't propagate to other elements, but it's probably not what you were looking for.
For being able to stop an event firing in other listeners, there needs to be an order of which the listeners are getting called. I believe the order is the order of registration of those listeners. From the design perspective, I don't think it would be a good idea to allow a listener to cancel/pause others.
Event propagation in HTML makes sense since it's about hierarchy, but here we don't have that (and even in case of events in HTML there can be multiple listeners for the single element).
There's no way to assign weight to listeners or define the order of importance, therefore it's not surprising that there isn't a way to stop the event.
Instead of letting listeners know about each other and manipulate each other, maybe you should try to think of another way to approach your problem (whatever that is).
Is that a consumer?
The StreamConsumer is just a class that you can implement if you want to allow other streams to be piped into your class.
Can I know that the stream has two listeners?
No, you have a ´Stream´ that wraps the DOM event handling. There is no such functionality.
Can I pause or cancel all other subscribers?
Look at Event.stopPropagation() and Event.stopImmediatePropagation(), and possibly Event.preventDefault().
If I write button.onClick.asBroadcastStream() again elsewhere, does it point to the same stream as was used in main?
[Updated] No, the current implementation doesn't gives you the same Stream back since the onClick getter returns a new stream every time it is invoked. However, the returned stream is already a broadcast stream so you shouldn't invoke asBroadcastStream() on it. If you do you will hower just get a reference to the same object back.
Stream<T> asBroadcastStream() => this;
Can I say in one of the handlers to not pass event on to the other broadcast listener? Is that a consumer?
Again, take a look at Event.stopPropagation() and Event.stopImmediatePropagation(), and possibly Event.preventDefault().
Can an OTP event manager process (e.g. a logger) have some state of its own (e.g. logging level) and filter/transform events based on it?
I also have a need to put some state into the gen_event itself, and my best idea at the moment is to use the process dictionary (get/put). Handlers are invoked in the context of the gen_event process, so the same process dictionary will be there for all handler calls.
Yes, process dictionaries are evil, but in this case they seem less evil than alternatives (ets table, state server).
The gen_event implementation as contained in the OTP does no provide means for adding state.
You could extend the implementation to achieve this and use your implementation instead of gen_event. However I would advise against it.
The kind of state you want to add to the event manager belongs really in the event handler for several reasons:
You might want to use different levels in different handlers, e.g. only show errors on the console but write everything to the disk.
If the event level would be changed in the manager event handlers depending on getting all unfiltered events might cease to function (events have more uses than just logging). This might lead to hard to debug problems.
If you want a event manager for multiple handlers that all only get filtered events you can easily achieve this by having two managers: one for unfiltered messages and one for e.g. level filtered messages. Then install a handler to the unfiltered one, filter in the handler by level (easy) and pass on the filtered events to the other manager. All handlers that only want to get filtered messages can be registered to the second manager.
The handlers can have their own state that gets passed on every callback like:
Module:handle_event(Event, State) -> Result
Filtering might look like this (assuming e.g. {level N, Content} events):
handle_event({level, Lvl, Content}, State#state{max_level=Max}) when Lvl >= Max ->
gen_event:notify(filtered_man, Content);
The State can be changed either by special events, by gen_event:call\3,4 (preferably) or by messages handled by handle_info.
For details see Gen_Event Behaviour and gen_event(3)
When you start_link a gen_event process - thing that you should always do via a supervisor -, you can merely specify a name for the new process, if you need/want it to be registered.
As far as I can see, there's no way to initiate a state of some sort using that behaviour.
Of course, you can write your own behaviour, on the top of a gen_event or of a simple gen_server.
As an alternative, you might use a separate gen_event process for each debugging level.
Or you can just filter the messages in the handlers.