From GitHub page of RxSwift
This is the most elaborate trait. Its intention is to provide an
intuitive way to write reactive code in the UI layer, or for any case
where you want to model a stream of data Driving your application.
- Can't error out.
- Observe occurs on main scheduler.
- Shares side
effects (share(replay: 1, scope: .whileConnected)).
Again copying from same page
Its intended use case was to model sequences that drive your
application.
Now coming back to differences?
Driver ensures that observe occurs only on main thread:
Drive is one of the traits in RxSwift that ensures observe occurs only on MainThread
, Which means no matter on what thread event is emitted and triggered driver, driver will always ensures to forward the event to next operator in the chain or to its subscribe block on main thread.
In Rx all events are propagated on the same thread in which the event occurred. So if you trigger a subject on say thread (100) using subject.onNext(
, its subscribe block will be called on the same thread (100) until and unless you use observedOn
or subscribedOn
operator to ensure the manual thread switching.
If you are driving your UI components from the observables/subjects in your viewModel, drivers make perfect sense. Assume you make API call to fetch data from server on background thread, you wouldn't wanna access your UI components on background thread, connecting/converting your observables/subjects to driver (using asDriver
and passing onErrorJustReturn
) and driving your UI components via driver will ensure your UI components are always accessed on main thread
Can't error out.
Normally when error occurs, subscription will be terminated and if you are driving your UI components you wouldn't want you subscription/bind to break every time there is an error event.
Example: Assume you drive your tableView via CoreData, and for some reason while fetching the data from CoreData an error occurred, if you don't use drive and had used plane bind(to:
its onError
will be triggered and its bind with UIComponent will be broken. If you fetch the data again you will have to re-establish this bind. For UI component error in fetching / procuring the data shouldn't make any difference. It should be simply a stream of events which changes its state.
bindTo
is nothing more than syntactic sugar coat on subscribe
so if you use bindTo
or subscribe
to drive UI components you will loose all the benefits drive
inherently brings to table.
You can always use observedOn
to ensure manual switching of thread to main
and also might have some retry mechanism to establish subscription back / retain subscription when an error occurs but ultimately you will end up writing your own drive trait
When should I use drive and when should I use bindTo
Thumb rule is are you trying to drive a UI component use drive
else use bindTo
. Generally if you want your subscribe to occur only on main thread and don't want your subscription to error out (like driving UI components) use driver
else stick with bindTo
or subscribe
EDIT 1:
OP's question in comment:
asDriver() in my example makes sure isEnabled is being observed on the
main thread and I don’t have to pass onErrorJustReturn because
BehaviorRelay also can’t fail? In this case drive() has the main
thread benefit but not the failsafe benefit?
in my example makes sure isEnabled is being observed on the main thread - YES
I don’t have to pass onErrorJustReturn because BehaviorRelay also can’t fail? - BINGO
If you check a bit deeper on BehaviorRelay you will find
/// BehaviorRelay is a wrapper for BehaviorSubject
.
/// /// UnlikeBehaviorSubject
it can't terminate with error or completed.
So clearly BehaviorRelay cant error out hence compiler is intelligent enough to understand and not to ask for onErrorJustReturn
. If you really wanna see one use BehaviorSubject
and compiler will ask for it :)
Credits to Daniel to point out my mistake, that drive isn't the only trait that ensures observe occurs only on MainThread
hence edited my answer to reflect the same. Thank you
asDriver().drive()
rather thanasObservable().bind()
? (I will but more detail into my question) – Cryptology