RxSwift — What It Is, Key Concepts, and Reactive Programming

Author: IT Sectr Published: 2026-03-17 Reading time: 8 min

RxSwift is a reactive programming library for Swift that implements the Observable pattern. According to ReactiveX, 2025, it is the most popular implementation of Reactive Extensions for the Apple ecosystem. Observable serves as an event source, while Observer subscribes to receive events.

Key Takeaways

  • RxSwift — an implementation of Reactive Extensions for Swift with support for Observable, Subject, and 300+ operators
  • Observable — an event source that emits values, errors, or a completion signal
  • Subject — simultaneously an Observable and Observer, allowing manual insertion of events into the stream
  • DisposeBag — an automatic memory management mechanism that unsubscribes subscriptions upon deallocation
  • Schedulers — manage execution threads, allowing switching between main and background queues

What is RxSwift?

RxSwift is a reactive programming library for the Swift language, ported from Reactive Extensions (Rx). It allows describing asynchronous and event-driven programs through Observable Sequence — a sequence of data available over time. iOS developers use RxSwift to handle network requests, UI events, and streaming data without nested callbacks.

Observable and Observer

The foundation of RxSwift consists of two key protocols: ObservableType — an event source that can emit three types of signals: .next(value), .error(error), and .completed. Observer subscribes to Observable via the subscribe method and receives these events. This model is called Reactive Streams and guarantees that no event is lost with a proper subscription.

Transformation Operators

RxSwift provides over 300 operators for working with streams: map transforms each event, filter passes only matching events, flatMap unfolds nested Observables into a single stream. Operators are chained together, creating a declarative data processing pipeline without side effects.

Traits: Single, Completable, Maybe

In addition to the basic Observable, RxSwift provides specialized wrapper types. Single emits exactly one value or an error — ideal for HTTP requests. Completable completes with success or failure without a value — for write operations. Maybe combines both scenarios: it can complete with a value, without a value, or with an error. These Traits simplify semantics and make code self-documenting.

How Reactive Programming Works in RxSwift

Reactive programming in RxSwift is built on the Observer pattern. ObservableSequence is analogous to Sequence from the standard library, but with asynchronous access to elements. The event stream is passed through a chain of operators, each returning a new ObservableSequence without mutating the original.

Operator Chains

Operators in RxSwift are pure functions that take one ObservableSequence and return a new one. For example, map creates a new sequence by applying a transformation to each element. By combining operators, the developer builds a pipeline where data goes through all processing stages without intermediate variables.

Schedulers and Execution Threads

Schedulers are an abstraction over execution threads in RxSwift. A Scheduler determines on which thread the code will execute: MainScheduler — the UI thread, SerialDispatchQueueScheduler — a background queue. The operators subscribeOn and observeOn specify where work is performed and where results are processed, respectively.

Core Components of RxSwift

RxSwift includes several basic types, each solving its own task in the reactive pipeline. Single is an Observable that emits exactly one value or an error, convenient for network requests. Completable completes with success or failure without a value. Maybe combines the properties of Single and Completable.

Subject and Relay

Subject is a hot Observable that also acts as an Observer. PublishSubject emits only new events to subscribers, BehaviorSubject — the last event plus new ones. Relay is a variant of Subject that does not emit .error or .completed, guaranteeing stream continuity. BehaviorRelay stores the current value and is suitable for State-driven UI.

DisposeBag

DisposeBag is a collection of Disposables that automatically unsubscribes all subscriptions upon its deallocation. In iOS, DisposeBag is typically added to UIViewController or UIView. When the screen is closed, DisposeBag is cleared — this prevents memory leaks and access to non-existent UI elements.

RxSwift Code Examples

Below is an example of creating an Observable from an array of data using the map operator to transform strings:

swift
let observable = Observable.of("Swift", "RxSwift", "Reactive")

observable
    .map { $0.uppercased() }
    .subscribe(onNext: { value in
        print("Received: \(value)")
    })
    .disposed(by: disposeBag)

The second example demonstrates combining two network requests using zip — the operator waits until both Observables emit a value and combines the results into a tuple:

swift
let first = fetchUser(id: "123")
let second = fetchPosts(userId: "123")

Observable
    .zip(first, second)
    .observe(on: MainScheduler.instance)
    .subscribe(onNext: { user, posts in
        updateUI(user: user, posts: posts)
    })
    .disposed(by: disposeBag)

The third example shows using BehaviorRelay to store state and automatically update the UI on changes: each state.accept() change immediately broadcasts to subscribers, which is ideal for State patterns in MVVM architecture.

swift
let state = BehaviorRelay(value: "idle")

state
    .subscribe(onNext: { status in
        print("Status: \(status)")
    })
    .disposed(by: disposeBag)

state.accept("loading") // Prints: Status: loading

RxSwift vs Other Approaches

RxSwift differs from traditional asynchronous methods (Delegation, NotificationCenter, Callback) in its declarative nature and composability. Unlike Combine, RxSwift supports iOS 9+ and has more operators. However, Combine is integrated into Foundation and SwiftUI at the language level, giving it an advantage in new Apple projects.

The main advantage of RxSwift over GCD (Grand Central Dispatch) is the ability to combine and transform data streams at the abstraction level rather than managing queues manually. However, RxSwift requires learning reactive concepts, which increases the entry threshold for the team.

In practice, RxSwift is used in large projects where reactive chains connect UI events, business logic, and network interaction in a single pipeline. For example, in trading applications, quote streams are processed via RxSwift: ticks arrive from WebSocket, go through filtering, are grouped by timeframe, and displayed on a chart in real time. Such a scenario is difficult to implement via Delegation or NotificationCenter without losing readability.

Alternatives to RxSwift include Combine (iOS 13+), AsyncSequence from Swift Concurrency (iOS 15+), as well as third-party libraries like ReactiveSwift without ties to Apple platforms. The choice depends on the minimum supported iOS version and developer experience. For new iOS 15+ projects, teams often choose AsyncSequence — it does not require library installation and uses native Swift language constructs.

Architectural patterns with RxSwift typically follow MVVM or Clean Architecture. ViewModel contains all business logic as Observable chains, and View subscribes to transformed data. The Input-Output pattern separates input events (taps, text input) from output states (button text, loader visibility). This approach simplifies testing: ViewModel is tested without UI through virtual Schedulers.

RxSwift is suitable for both small projects with a few screens and large enterprise applications with dozens of modules. In large projects, reactive chains permeate the entire architecture: from UserDefaults observation via RxProperty to network requests through Moya (an RxSwift wrapper over Alamofire). Each module is isolated and communicates via reactive interfaces, which simplifies implementation replacement without changing subscribers. With proper architecture, RxSwift reduces the amount of code compared to classical approaches, since there is no need to write boilerplate for KVO, Target-Action, or NotificationCenter.

RxSwift is actively used in projects with RxDataSources — a library for reactive work with UITableView and UICollectionView. RxDataSources automatically computes the difference between old and new sets of cells and applies animated changes. This relieves the developer from manual work with beginUpdates/endUpdates and eliminates crashes due to data inconsistency.

For debugging RxSwift chains, there is the debug() operator — it logs all events: subscribe, next, error, completed, dispose. This is an indispensable tool when developing complex reactive pipelines. debug(String) takes an identifier that appears in the logs. For memory profiling, RxSwift.Resources.total shows the total number of active Observables and Disposables in the application — helps identify leaks when DisposeBag is not cleared or a retain cycle holds a subscription. The additional operator takeUntil(self.rx.deallocated) automatically cancels the subscription upon object deallocation — this is another layer of leak protection.

RxSwift Best Practices

When writing RxSwift code, it is important to follow the principle of single Observable per subscription: each ViewController should not create more than one Subscription to the same Observable — this reduces the risk of race conditions. For memoization of Observables, the share() operator is used, which turns a cold Observable into a hot one with a replay buffer of size 1. When working with shared resources, use connect() to control the start of emission — this guarantees that all subscribers connect before the first event.

Testing RxSwift code is done through TestScheduler — a virtual Scheduler that allows managing time. testScheduler.createHotObservable(values) creates an Observable with a predefined sequence of events by virtual time. testScheduler.start() starts processing. TestScheduler allows checking in what order and at what virtual timestamp events occur, without real delays, making tests fast and deterministic.

Frequently Asked Questions

What is the difference between Observable and Subject in RxSwift?

Observable is a cold source: it does not emit events until subscription. Subject is hot: it emits events regardless of subscribers and allows manual insertion of values via onNext. PublishSubject passes only new events, BehaviorSubject — the last one plus new ones.

How does DisposeBag prevent memory leaks in RxSwift?

DisposeBag stores all Disposable subscriptions. When DisposeBag is deallocated (for example, when a ViewController is closed), all stored subscriptions are automatically canceled. This guarantees that Observable will not send an event to a destroyed UI object.

What to choose: RxSwift or Combine for a new iOS project?

If the minimum iOS version is 13+ and the team knows SwiftUI — choose Combine. If the project supports iOS 12 and below or requires a larger set of operators — RxSwift. Combine offers better integration with Foundation (URLSession, Timer, NotificationCenter).

How do Schedulers work in RxSwift?

Schedulers abstract execution threads. subscribeOn specifies on which Scheduler the subscription is performed (usually background). observeOn determines on which Scheduler events are received (most often MainScheduler for UI updates). SerialDispatchQueueScheduler works through GCD.

Can RxSwift be used with SwiftUI?

Yes, RxSwift can be integrated with SwiftUI via ObservableObject. Use BehaviorRelay as @Published properties: subscription to Relay broadcasts changes to Combine, and SwiftUI redraws the View through @ObservedObject. This is a popular migration pattern from UIKit to SwiftUI.

Summary

  • RxSwift — a reactive programming library based on Reactive Extensions and the Observable pattern
  • Observable emits three types of signals: .next, .error, and .completed
  • Subject (PublishSubject, BehaviorSubject) combines Observable and Observer for hot streams
  • DisposeBag manages the lifecycle of subscriptions and prevents memory leaks
  • Operators (map, filter, flatMap, zip) allow building declarative processing chains
  • Schedulers switch execution between background queues and the UI thread
  • For new iOS 13+ development, consider Combine as a built-in alternative

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also