Disposing
There is one additional way an observed sequence can terminate. When we are done with a sequence and we want to release all of the resources allocated to compute the upcoming elements, we can call dispose
on a subscription.
Here is an example with the interval
operator.
let subscription = Observable<Int>.interval(0.3, scheduler: scheduler)
.subscribe { event in
print(event)
}
Thread.sleep(forTimeInterval: 2.0)
subscription.dispose()
This will print:
0
1
2
3
4
5
Note that you usually do not want to manually call dispose
; this is only educational example. Calling dispose manually is usually a bad code smell. There are better ways to dispose subscriptions. We can use DisposeBag
, the takeUntil
operator, or some other mechanism.
So can this code print something after the dispose
call executed? The answer is: it depends.
If the
scheduler
is a serial scheduler (ex.MainScheduler
) anddispose
is called on on the same serial scheduler, the answer is no.Otherwise it is yes.
You can find out more about schedulers here.
You simply have two processes happening in parallel.
- one is producing elements
- the other is disposing the subscription
The question "Can something be printed after?" does not even make sense in the case that those processes are on different schedulers.
A few more examples just to be sure (observeOn
is explained here).
In case we have something like:
let subscription = Observable<Int>.interval(0.3, scheduler: scheduler)
.observeOn(MainScheduler.instance)
.subscribe { event in
print(event)
}
// ....
subscription.dispose() // called from main thread
After the dispose
call returns, nothing will be printed. That is guaranteed.
Also, in this case:
let subscription = Observable<Int>.interval(0.3, scheduler: scheduler)
.observeOn(serialScheduler)
.subscribe { event in
print(event)
}
// ...
subscription.dispose() // executing on same `serialScheduler`
After the dispose
call returns, nothing will be printed. That is guaranteed.
Dispose Bags
Dispose bags are used to return ARC like behavior to RX.
When a DisposeBag
is deallocated, it will call dispose
on each of the added disposables.
It does not have a dispose
method and therefore does not allow calling explicit dispose on purpose. If immediate cleanup is required, we can just create a new bag.
self.disposeBag = DisposeBag()
This will clear old references and cause disposal of resources.
If that explicit manual disposal is still wanted, use CompositeDisposable
. It has the wanted behavior but once that dispose
method is called, it will immediately dispose any newly added disposable.
Take until
Additional way to automatically dispose subscription on dealloc is to use takeUntil
operator.
sequence
.takeUntil(self.rx.deallocated)
.subscribe {
print($0)
}