The fundamental building block of RxSwift is the observable sequence. Synonyms of observable sequence are observable, sequence, or data stream. In the rest of this series, we refer to observable sequences as observables.

An observable is a sequence that can be observed by other objects hence the name observable sequence. An observable asynchronously emits events. This simply means that an observable emits events independently of the main application flow.

Marble Diagrams

Observables are often represented by marble diagrams. A marble diagram visualizes the events of an observable over time. Take a look at this example. The horizontal line represents time and each circle on the line represents an event. The marble diagram visualizes the asynchronous nature of an observable. The events of the observable are asynchronously emitted over time.

Marble Diagram

An observable can emit three types of events, a next event, an error event, and a completed event. Each next event encapsulates an element. In this marble diagram, the observable emits elements of type Int. Each next event encapsulates an element of type Int.

Marble Diagram

An observable emits an error event if something goes wrong. It won't emit any other events after emitting an error event.

Marble Diagram

The same is true for the completed event. The completed event signifies the end of the observable. It won't emit any other events after emitting a completed event.

Marble Diagram

Exploring Observables

Let's take a look at a few examples to make what you learned more tangible. We use the finished project of the previous episode as a starting point. Clear the contents of the playground with the exception of the import statements at the top.

import RxSwift
import Foundation

The Observable class defines a number of static methods to create observables. One of the simplest options you have to create an observable is by invoking the just(_:) method. It accepts an element as its only argument and it returns an observable.

We define a constant, observable, to keep a reference to the observable. We define the type of elements the observable emits in angle brackets and invoke the just(_:) method, passing in the element the observable emits, an integer in this example.

import RxSwift
import Foundation

let observable = Observable<Int>.just(1)

The observable won't emit any events just yet. We first need to create a subscription by invoking the subscribe(_:) method on the observable, passing in a closure or event handler. The closure or event handler is executed every time the observable emits an event. It accepts the emitted event as its only argument.

import RxSwift
import Foundation

let observable = Observable<Int>.just(1)

observable.subscribe { (event) in

}

An event is of type Event, an enum. We can use a switch statement to switch on the event. Remember that RxSwift defines three possible events, next, error, and completed. The next event has an element as its associated value and the error event has an error as its associated value.

import RxSwift
import Foundation

let observable = Observable<Int>.just(1)

observable.subscribe { (event) in
    switch event {
    case .next(let element):
        print(element)
    case .error(let error):
        print(error)
    case .completed:
        print("completed")
    }
}

Run the contents of the playground and inspect the output in the console. The output shows what type of observable the just(_:) method creates. The observable emits a single next event and a completed event. The element of the next event is the element we passed to the just(_:) method to create the observable. In other words, the just(_:) method creates an observable that emits a single element.

1
completed

Press Command and click the next case in the switch statement to navigate to its definition in the RxSwift library. The Event enum defines the possible event types an observable can produce, next, error, and completed.

/// Represents a sequence event.
///
/// Sequence grammar: 
/// **next\* (error | completed)**
public enum Event<Element> {

    /// Next element is produced.
    case next(Element)

    /// Sequence terminated with an error.
    case error(Error)

    /// Sequence completed successfully.
    case completed
}

RxSwift defines several methods to subscribe to an observable. Another option that I use often is a variant of the subscribe(_:) method. The subscribe(onNext:onError:onCompleted:onDisposed:) method accepts an event handler for each event type. This is sometimes more convenient because the onNext event handler accepts the element of the next event and the onError event handler accepts the error of the error event.

import RxSwift
import Foundation

let observable = Observable<Int>.just(1)

observable.subscribe(onNext: { (element) in
    print("on next", element)
}, onError: { (error) in
    print("on error", error)
}, onCompleted: {
    print("on completed")
}) {
    print("on disposed")
}

You can ignore the onDisposed event handler for now. We cover disposing and disposables later in this series. Run the contents of the playground and inspect the output in the console. The onNext and onCompleted event handlers are executed once. The onDisposed event handler is also executed once.

on next 1
on completed
on disposed

Zero or More Elements

Empty

Let's explore a few more methods to create observables. The empty() method doesn't accept any arguments and you can probably guess what type of observable it creates. Let's try it out.

import RxSwift
import Foundation

// let observable = Observable<Int>.just(1)
let observable = Observable<Int>.empty()

Run the contents of the playground and inspect the output in the console. No next or error events are emitted by the observable. It only emits a completed event. As the name of the method implies, the resulting observable doesn't emit any elements.

on completed
on disposed

You may be wondering why it's useful to create an observable that emits no next events. We cover that later in this series.

Never

The never() method creates an observable that doesn't emit any events, not even a completed event. Let's give it a try. The console remains empty when we run the contents of the playground because the resulting observable doesn't emit any events.

import RxSwift
import Foundation

// let observable = Observable<Int>.just(1)
// let observable = Observable<Int>.empty()
let observable = Observable<Int>.never()

of(_:) and from(_:)

The of(_:) method accepts a single, variadic parameter. This simply means that it accepts zero or more objects of the same type. Create an observable by invoking the of(_:) method, passing in a handful of integers.

import RxSwift
import Foundation

// let observable = Observable<Int>.just(1)
// let observable = Observable<Int>.empty()
// let observable = Observable<Int>.never()
let observable = Observable<Int>.of(1, 2, 3, 4, 5)

Run the contents of the playground and inspect the output in the console. Because we passed five integers to the of(_:) method, five next events are emitted by the observable. The last event is a completed event.

on next 1
on next 2
on next 3
on next 4
on next 5
on completed
on disposed

We can create the same observable by invoking the from(_:) method on the Observable class. This method also accepts a single argument. The difference is that the elements are contained in an array.

import RxSwift
import Foundation

// let observable = Observable<Int>.just(1)
// let observable = Observable<Int>.empty()
// let observable = Observable<Int>.never()
// let observable = Observable<Int>.of(1, 2, 3, 4, 5)
let observable = Observable<Int>.from([1, 2, 3, 4, 5])

The output in the console is identical, though.

on next 1
on next 2
on next 3
on next 4
on next 5
on completed
on disposed

Interval and Timer

It's also possible to create observables that emit events at regular time intervals. The interval(_:scheduler:) method creates such an observable. The first argument of the interval(_:scheduler:) method is of type RxTimeInterval, an alias for DispatchTimeInterval. DispatchTimeInterval is defined in the Dispatch framework and is an enum that represents a time interval. The second argument of the interval(_:scheduler:) method is a scheduler. Don't worry about this for now. We cover schedulers later in this series.

import RxSwift
import Foundation

// let observable = Observable<Int>.just(1)
// let observable = Observable<Int>.empty()
// let observable = Observable<Int>.never()
// let observable = Observable<Int>.of(1, 2, 3, 4, 5)
// let observable = Observable<Int>.from([1, 2, 3, 4, 5])
let observable = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)

The observable we create emits a next event every second.

on next 0
on next 1
on next 2
on next 3
on next 4
on next 5

The timer(_:period:scheduler:) method is similar in some ways. As the name of the method implies, it can be used as a timer. It accepts three arguments. The first argument is of type RxTimeInterval and defines when the observable emits its first next event. The second argument is of an optional type. If you specify a time interval, then the observable emits subsequent next events at regular time intervals. The last argument is a scheduler.

import RxSwift
import Foundation

// let observable = Observable<Int>.just(1)
// let observable = Observable<Int>.empty()
// let observable = Observable<Int>.never()
// let observable = Observable<Int>.of(1, 2, 3, 4, 5)
// let observable = Observable<Int>.from([1, 2, 3, 4, 5])
// let observable = Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance)
let observable = Observable<Int>.timer(.seconds(2), period: .seconds(3), scheduler: MainScheduler.instance)

The resulting observable produces its first next event after two seconds and it emits a next event every three seconds after that.

on next 0
on next 1
on next 2
on next 3
on next 4
on next 5

What's Next?

There are several other methods to create observables, but you should now have a good understanding of what an observable is and what its features are. We continue to use observables throughout this series so it's important that you understand what we covered in this episode.