Reactive Programming in Swift: Combine and RxSwift for iOS/macOS

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Reactive Programming in Swift: Combine and RxSwift



Reactive programming is a paradigm oriented towards asynchronous data streams and the propagation of changes. In the Swift ecosystem (iOS/macOS), the main tools for implementing this paradigm are the Combine framework (built into the Apple SDK) and the third-party library RxSwift. Both tools allow you to declaratively describe event handling, reducing the number of callback functions and making code more readable and predictable.



In this article, we will look at the key concepts of reactive programming, compare Combine and RxSwift, and provide practical examples for iOS and macOS.



Key Concepts

The reactive approach is based on three entities:



  • Publisher (Observable) — a data source that generates events (values, errors, completion).
  • Subscriber (Observer) — a consumer that reacts to events.
  • Operator — a function that transforms the data stream (filtering, transformation, combination).


Example of a simple Publisher in Combine:

import Combine

let publisher = Just("Hello, Reactive World!")let subscription = publisher.sink { value in print(value)}// Output: Hello, Reactive World!


Combine vs RxSwift: Comparison

Both frameworks solve similar tasks but have differences:



  • Combine — a native Apple framework (iOS 13+, macOS 10.15+). It uses strong typing and integrates with SwiftUI and URLSession.
  • RxSwift — a cross-platform library with a large community. It supports older iOS versions (starting from iOS 8).
  • Performance: Combine is optimized for Apple Silicon, RxSwift can be more flexible in custom scenarios.


Code Examples for iOS/macOS



1. Reactive Text Field Handling (Combine + UIKit)

Subscribing to text changes in UITextField:

import UIKitimport Combine

class ViewController: UIViewController { @IBOutlet weak var textField: UITextField! private var cancellables = Set<AnyCancellable>() override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.publisher(for: UITextField.textDidChangeNotification, object: textField) .compactMap { ($0.object as? UITextField)?.text } .debounce(for: .milliseconds(500), scheduler: RunLoop.main) .sink { text in print("User entered: \\(text)") // Here you can make a network request or update the UI } .store(in: &cancellables) }}


2. Combining Multiple Streams (RxSwift for macOS)

Example of merging two observable sequences:

import RxSwift

let disposeBag = DisposeBag()

let firstObservable = Observable.of(1, 2, 3)let secondObservable = Observable.of("A", "B", "C")

Observable.zip(firstObservable, secondObservable) .subscribe(onNext: { (number, letter) in print("\\(number) -> \\(letter)") }) .disposed(by: disposeBag)

// Output:// 1 -> A// 2 -> B// 3 -> C


3. Handling a Network Request Using Combine

Using URLSession to load data:

import Combineimport Foundation

struct Post: Decodable { let id: Int let title: String}

func fetchPosts() -> AnyPublisher<[Post], Error> { let url = URL(string: "https://jsonplaceholder.typicode.com/posts")! return URLSession.shared.dataTaskPublisher(for: url) .map(\\.data) .decode(type: [Post].self, decoder: JSONDecoder()) .eraseToAnyPublisher()}

Recommendations