RxSwift: Finite and Infinite Observables

Vaibhav Singh
5 min readOct 23, 2021

--

In this article, I am planning to cover a brief introduction to observables and their creation in RxSwift.

This belongs to the folks at Raywenderlich.com

Observables are immutable sequences of data or events to which other objects/ consumers can react, by subscribing to them. The events or values are asynchronously emitted over time and observables produce a sequence of these events that carry an immutable screenshot of the events.

The life cycle of an observable includes the following events which are actually represented as an enum.

When an observable emits an element, it's known as a next event. As we can see in the screenshot above, Event has a generic Element attached to it, since Events are sequences and Element is a generic sequence type. The next event gives us an Element.

There are 2 ways for an observable to end, either it completes successfully, which is the completed case above, or it results in an error and terminates, where it emitted the error event containing the error. In both cases, the observable terminates and can’t emit any more events.

There is another lifecycle event called .dispose, which can be called on a subscription to dispose it off.
.completed and .error events call dispose automatically.

Creating Observables

Let’s look into different ways of creating observables.

There are two kinds of observables, finite and infinite. Finite ones don’t require us to manage memory, they dispose off by themselves. But the infinite ones require us to take care of memory management.

Finite Observable creation

1) just: Create an observable sequence containing just a single element. It is a static method on Observable. In RxSwift methods are called operators.

Since just is a finite observable it automatically calls dispose and completed and frees up memory.

2) of: Convert any swift type to its corresponding Observable sequence.

Observable.of(1,2,3)

It might seem like the type of the observable is an array of integers since we have several integers, but the type is Integer as the of operator has a variadic parameter.

We can however pass an array to of as well

Observable.of([1, 2, 3])
Here the type will be an array of Integers.

Of is again a finite observable so we don’t need to think about memory management when using of. It behaves like a constant after we initialize it with values, we can’t add after that.

3) from: The from operator creates an observable of individual elements from an array of typed elements. It only takes in an array. It also acts as a constant once initialized, new values can’t be added.

Subscribing to observables

Before we move on to infinite observable creation, let’s look at subscribing observables. An observable won’t send events or perform any work until it has a subscriber.

Say we have an observable of Integers, we can subscribe to it as shown below

Option-click on the subscribe operator, and observe it takes a closure parameter that receives an Event of type Int and doesn’t return anything, and subscribe returns a Disposable

We can get the element from the event as shown below

We can also add handlers for each event type an observable can emit. A next event passes the element being emitted to the handler, and an error event contains an error instance

The onNext closure receives the next event’s element as an argument, so you don’t have to manually extract it from the event like you did before.

Disposing and terminating

A subscription triggers an observable’s work, causing it to emit new events until an error or completed event terminates the observable. However, we can also manually cause an observable to terminate by canceling a subscription to it.

To explicitly cancel a subscription, call dispose() on it. After we cancel the subscription or dispose of it, the observable will stop emitting events.

Instead of managing each subscription, we can use dispose bags. A dispose bag holds disposables — typically added using the disposed(by:) method — and will call dispose() on each one when the dispose bag is about to be deallocated.

Infinite observable creation

  • create: Create operator is another way to create Observables. It takes in a single param named subscribe. Its job is to provide the implementation of calling subscribe on the observable.

The subscribe parameter is an escaping closure that takes an AnyObserver and returns a Disposable. AnyObserver is a generic type that facilitates adding values onto an observable sequence, which will then be emitted to subscribers

So here we are creating observable using the create operator, and inside the closure, we define all the events.

NOTE: we are calling onNext, OnCompleted, etc on the observer which is taken in by the subscribe closure, not on the observable itself, we can’t call these operators on an observable, observables can just be observed.

In the last line, we return a disposable as the subscribe closure is supposed to return a disposable representing the subscription.

When working with the create operator it's our responsibility to manage memory by calling completed, error, and dispose.

When we subscribe to an Observable, the Disposable keeps a reference to the Observable and the Observable keeps a strong reference to the Disposable. To break the retain cycle we need to call dispose on the Observable. If Observable ends by itself (by sending completed or error) it will automatically break the retain cycle. In any other scenario, the responsibility to call the dispose function is in our hands.

I hope this article was a nice introduction to observables in RxSwift, I am planning to cover the observers next.

--

--

Vaibhav Singh
Vaibhav Singh

Written by Vaibhav Singh

iOS Engineer @ Pulselive Leading development of the Premier League App!

No responses yet