Manage memory in RxSwift with Dispose Bag

Tram Ho

Many people who are new to RxSwift will ask questions about Dispose Bag. So, what is a Dispose Bag? How to use them? We will find out in this article.

Concept

First, let’s talk about Disposable. Disposable is not a standard concept in general iOS programming, it is used in RxSwift and is the way RxSwift manages its memory. This article will answer some questions about Disposable as well as ARC memory management mechanism and how to avoid Memory Leak while using Rx.

Observable and memory management

RxSwift is a library that helps us solve asynchronous events, so reference counting (anyone who has read about ARC in iOS will understand this concept) is what we need. mind. To better understand let’s analyze the example below

Cancel or NOT cancel? Imagine we have an Observable that is responsible for calling the API. When you call a subcribe (usually located in ViewDidLoad), it will send the request to the server and wait for a response. This is a simple and typical case, but please note, users can return to the previous screen at any time. With the normal memory management mechanism, when returning to the previous screen, the current UIViewController will be deallocate and will also cancel the Observable because it has lost the link from UIViewController. And of course, our request will not be complete in that case. In some cases, you want the Observable to exist until the request is completed and receive a response, even if the user has returned to the previous screen. Therefore, the developer should decide when Observable will be canceled.

Memory is limited resources

Observables can hold a number of variables that are passed in or declared when defining them. That means Observable will assign a piece of memory to store those values. On the other hand, a property of Observable is that it will stop sending events when it receives an error or is completed. Meanwhile, the storage of Observable resources is not necessary, it is best to free up the memory that Observable holds. To do that, we need to be able to “clean” Observable when required. That’s why the Subcribe Method will always return Disposable

Disposable

Disposable is a protocol with a dispose () method. When subcribe to an Observable, the Disposable will keep a strong link to the Observable, and the Observable will also hold a strong link that points back to the Disposable. Thanks to that, if the user has back to the previous screen, Observable will not be deallocated unless you want it deallocated. To break this type of retain cycle, you must call the dispose function in Observable. If the Observable terminates itself (emit out completed or error), it will automatically break retain cycle. In other cases, the responsibility to call the dispose function is done by us.

The simplest way to call dispose in the denit function of ViewController

The solution is simple, but imagine how many dispose () lines will need to be added to denit () when you subcribe a lot of Observable. The extension becomes more complicated when you have to change the code in many places. To improve that, you can use the [Disposable] array. Usage as follows

Looks much better, the extension is simpler. However, we can improve the code even further. We will use DisposeBag instead of [Disposable]

Wait. Why not write in denit anymore. So when will it call to dispose ??? DisposedBag will call to dispose when the viewcontroller containing it is denit. DisposeBag will unlink from UIViewController to it => ARC = 0 and it is dellocated and calls all disposables.

DisposeBag and Retain Cycle

With DisposedBag, if not careful you will easily create Retain Cycles between Observable and UIViewController. Meanwhile, DisposeBag will wait to be dellocate forever and of course not dispose away any of its disposables. What you need to keep in mind is that for each operator it will default to holding strong links to any variable used in its closure. See the example below to better understand

The above code caused Retain Cycles, the reason is because adding Disposable to DisposeBag means that DisposeBag will hold a strong link to Disposbale. Disposable keeps Observable alive. Observable again has a strong link to VIewController because self is used inside the map closure. And finally ViewController has a strong link to DisposeBag. BOOM !. You already have a retain cycle.

To solve that phenomenon, we can use Capture list or [weak self] and [unowned self]. A few small changes may solve your problem

Use self! = Retain cycle

Not just using self will cause the retain cycle, but it usually happens when self also holds DisposeBag.

summary

DisposeBag is not something magical but simply an array with many Disposable inside. It helps us automatically dispose the disposables without having to write manually. However, pay attention to the Retain Cycle phenomenon that it may cause.

Reference source: http://adamborek.com/memory-managment-rxswift/

Share the news now

Source : Viblo