Combine Introductions

In iOS 13/macOS Catalina, however, Apple brought reactive programming support to its ecosystem via the build in system framework combine.
Combine is Apple’s framework for managing asynchronous events in a declarative way. It allows you to process values over time, such as network responses, user input, or even timer updates. The framework relies on three main components: PublishersOperators, and Subscribers.

What Are Publishers?

Publisher is a component that emits a sequence of values over time. It defines how values or errors are produced and made available to subscribers. Publishers are used to represent data streams, such as:

  • Notifications
  • User interactions (e.g., button taps)
  • Network responses
  • Timer events
import Combine

let publisher = Just("Hello, Combine!")
publisher.sink { value in
    print(value) // Outputs: Hello, Combine!
}

Every publisher can emit multiple events of these three types:

  1. An output value of the publisher’s generic Output type.
  2. A successfull completion
  3. A completion with an error of the publisher’s Failure type.

The publisher protocol is generic over two types,
Publisher.Output is the type of the output values of the publisher. If the publisher is specialized as an Int, it can never emit a String or Date value.
Publisher.Failer is the type of error the publisher can throw if it fails, If the publisher can never fail, you specify that by using never failure type.

What Are Operators?

Operators are methods that transform, filter, or manipulate the values emitted by publishers. They allow you to create complex data pipelines while keeping your code declarative and clean.

Common Operators:

  • map: Transforms each value.
  • filter: Filters out unwanted values.
  • flatMap: Flattens nested publishers.
  • combineLatest: Combines multiple publishers.
let numbers = [1, 2, 3, 4, 5]
let publisher = numbers.publisher

publisher
    .filter { $0 % 2 == 0 } // Emits only even numbers
    .map { $0 * 10 }        // Multiplies each value by 10
    .sink { print($0) }     // Outputs: 20, 40