Combine: what it is, key concepts, and Publisher with Subscriber

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

Combine is a reactive programming framework from Apple, introduced in iOS 13. According to Apple Documentation, 2025, Combine provides a unified declarative API for handling asynchronous events. Publisher defines the data source, and Subscriber subscribes to receive data.

Key Takeaways

  • Combine — a built-in Apple framework for reactive programming, available since iOS 13
  • Publisher — a protocol that defines a source of Output values with a possible Failure error
  • Subscriber — a protocol that receives values from Publisher with demand management
  • Subject — a Publisher that allows manual event injection (PassthroughSubject, CurrentValueSubject)
  • Operators — map, filter, combineLatest, flatMap for transforming and combining streams

What is Combine?

Combine is a declarative Swift framework for processing asynchronous events over time. Unlike callback-based approaches, Combine allows you to describe data processing pipelines through a chain of operators. The framework is integrated with Foundation (URLSession, Timer, NotificationCenter) and SwiftUI (ObservableObject, @Published).

Publisher Protocol

Any type that implements the Publisher protocol must define Output (value type) and Failure (error type). A Publisher is not active until subscribed — it starts emitting events only after subscribe is called. This is cold semantics, characteristic of reactive streams, improving efficiency.

Subscriber Protocol

Subscriber receives events through three methods: receive(subscription:) — confirmation of subscription with demand management; receive(_:) — receiving a new value; receive(completion:) — stream completion with success or error. Demand specifies how many values the Subscriber is ready to accept — this is the backpressure mechanism.

Built-in Publishers

Apple provides many built-in Publishers: Just emits a single value and completes, Future — an asynchronous result with a closure, Deferred — deferred creation of a Publisher until subscription. URLSession.dataTaskPublisher converts a network request into a reactive stream. Timer.publish creates a periodic timer. NotificationCenter.default.publisher turns notifications into a Publisher. These integrations allow subscribing to events without manual bridging.

Publisher and Subscriber in Combine

In Combine, Publisher and Subscriber are connected through the Subscription protocol. Subscription is a connecting object that controls the data flow. Developers don’t need to create their own Publisher types — Apple provides built-in ones: Just, Future, Deferred, Fail, Empty, as well as Publishers for URLSession and Timer.

Subject in Combine

Subject is a Publisher that allows manually sending values. PassthroughSubject does not store state: a subscriber only receives events that occurred after subscription. CurrentValueSubject, similar to BehaviorRelay in RxSwift, stores the current value and immediately passes it to new subscribers.

Backpressure

The backpressure mechanism in Combine regulates data transfer speed. The Subscriber tells the Publisher through subscription.request(.unlimited) or subscription.request(.max(N)) how many values it is ready to process. This prevents buffer overflow when producer and consumer speeds are uneven.

Combine Operators

Combine includes more than 100 operators, divided into categories: transformation (map, tryMap, flatMap), filtering (filter, compactMap, removeDuplicates), combining (combineLatest, merge, zip), time management (debounce, throttle, delay), and error handling (catch, replaceError, retry).

The combineLatest operator combines the latest values from two Publishers — each time either emits a new value, the closure is called with both updated values. This operator is indispensable for form validation where you need to track the state of multiple input fields simultaneously.

The debounce operator delays value publication until a specified interval passes without new events. This is critical for search fields: the server request is sent only after the user stops typing for 300–500 ms, reducing load by 5–10 times.

Error Handling

Combine offers several error handling strategies at the operator level. catch intercepts Failure and replaces the Publisher with a fallback — the stream continues without crashing. replaceError(with:) provides a default value instead of an error. retry(_:) retries the subscription a specified number of times on failure. Importantly, a Never error type in the Publisher signature guarantees the stream will never fail — this allows using Publisher in SwiftUI without Failure handling.

Combine Code Examples

The first example shows basic usage of Just — a Publisher that emits a single value and completes:

swift
let publisher = Just("Hello Combine")

publisher
    .sink(receiveCompletion: { completion in
        print("Completed: \(completion)")
    }, receiveValue: { value in
        print("Received: \(value)")
    })

The second example demonstrates Combine integration with URLSession for a network request with result processing on the main thread:

swift
let url = URL(string: "https://api.example.com")!

URLSession.shared
    .dataTaskPublisher(for: url)
    .map { $0.data }
    .receive(on: DispatchQueue.main)
    .sink(receiveCompletion: { completion in
        if case .failure(let error) = completion {
            print("Error: \(error)")
        }
    }, receiveValue: { data in
        print("Data received: \(data.count)")
    })

The third example shows using CurrentValueSubject for state management:

swift
let counter = CurrentValueSubject<Int, Never>(0)

counter
    .sink { value in
        print("Counter: \(value)")
    }

counter.send(1) // Prints: Counter: 1
counter.send(2) // Prints: Counter: 2
print(counter.value) // Prints: 2

Combine vs RxSwift

Combine and RxSwift solve the same problem — reactive programming — but with different approaches. Combine is a native Apple framework built into the system: no dependency installation required, integrated with SwiftUI and Foundation. RxSwift is a third-party library with support for iOS 9+ and a wider set of operators.

Combine performance is higher in typical scenarios thanks to native C implementation. RxSwift provides more debugging tools (RxSwift.Resources.total, Debug), but its object-oriented architecture may be less efficient on large data streams. The choice between them is a trade-off between capabilities and integration.

An important difference is the backpressure model. In Combine, the Subscriber manages demand through Subscription, giving explicit control over stream speed. In RxSwift, backpressure is not controlled by default — Observable emits all values, and Subscriber processes them as they arrive. For large data streams, Combine is more predictable and memory-safe.

Combine is deeply integrated with SwiftUI at the language level. @Published generates a Publisher, ObservableObject provides objectWillChange Publisher. SwiftUI View automatically subscribes to these Publishers and redraws on changes. For UIKit there are third-party wrappers like CombineCocoa, but Combine was originally designed for SwiftUI, so its UIKit integration requires additional code. RxSwift, on the other hand, has a rich ecosystem for UIKit: RxCocoa provides reactive wrappers for all UI elements.

Combine supports integration with Core Data through NSFetchedResultsController Publisher. The Publisher emits new data on every Core Data stack change: adding, deleting, updating records. This allows building reactive lists without manually calling reloadData. By combining Combine with NotificationCenter Publisher for UIApplication.willResignActiveNotification, developers create a reactive layer for the entire application lifecycle without delegates and callbacks. For ObservableObject classes, SwiftUI automatically updates the View when @Published properties change — Combine handles the entire chain without a single line of manual code. Unit testing Combine code is done through XCTestExpectation and Publisher.sink in test cases with Scheduler isolation via ImmediateScheduler.

When working with Combine in UIKit projects, developers often subscribe via sink and store AnyCancellable in a Set. Typical pattern: ViewController creates a view, stores cancellables, subscribes to Publisher from ViewModel. On deinit, all subscriptions are automatically cancelled through the Cancellables collection. For proper UIControl handling in Combine, you can use UIControl.Event Publisher through the publisher(for:) extension.

Combine debugging is done through the print() or handleEvents() operator. print(String) logs all events: receive subscription, request demand, receive value, receive completion. handleEvents provides finer control: you can specify closures for each stage of the Publisher lifecycle. For testing, there is CombineExpectations — a library that allows checking that a Publisher emits expected values in tests with virtual time and demand control.

Combine in Practice

Combine is actively used in SwiftUI for form management: each @Published property generates a Publisher, SwiftUI subscribes to it through View.body. By combining multiple Publishers via combineLatest, form validation becomes declarative: each Publisher tracks one field, combineLatest collects all values, map validates them and returns the Submit button status. Publishers.Merge combines multiple Publishers of the same type into one — useful for collecting events from different controls into a single stream.

For Combine integration with UIKit, use UIControl Publisher through an extension: button.publisher(for: .touchUpInside) returns a Publisher that emits an event on tap. CombineCocoa is a community library providing Publishers for all UIControl events, UITextView.text, UIScrollView.contentOffset. On unsubscription, the cancellables Store is cleared in deinit, guaranteeing that no subscription outlives its owner. For UIControl with multiple states, use Publishers.MergeMany to combine Publishers into an array.

Frequently Asked Questions

Which iOS version is Combine available from?

Combine is available from iOS 13, macOS 10.15, tvOS 13, and watchOS 6. This limits its use in projects requiring support for older versions. For iOS 12 and below, RxSwift or third-party libraries are used.

How is PassthroughSubject different from CurrentValueSubject?

PassthroughSubject does not store state and does not replay the last value to new subscribers — they only receive future events. CurrentValueSubject stores the current value and immediately passes it to new subscribers. CurrentValueSubject.value allows reading and writing the current value synchronously.

How does Combine integrate with SwiftUI?

Combine is at the core of SwiftUI: @Published generates a Publisher, ObservableObject uses objectWillChange Publisher. SwiftUI View automatically subscribes to @ObservedObject and @StateObject through the Combine pipeline, redrawing the View when properties change.

What is backpressure in Combine?

Backpressure is a mechanism for controlling data transfer speed. The Subscriber tells the Subscription how many values it is ready to process (demand). The Publisher cannot emit more than requested. This is critical when working with large data streams from network sockets.

How to handle errors in Combine?

The catch operator intercepts an error and replaces the Publisher with a fallback. replaceError replaces the error with a default value. retry retries the subscription a specified number of times on error. All operators should be placed before subscribe to prevent crashes on Failure.

Summary

  • Combine — a built-in Apple framework for reactive programming since iOS 13
  • Publisher — a protocol with Output and Failure, starts work after subscription
  • Subscriber — receives values via receive with demand management support
  • Subject (PassthroughSubject, CurrentValueSubject) — Publisher with manual event injection
  • Operators map, filter, combineLatest, debounce, catch — the foundation of pipelines
  • Backpressure via demand prevents Subscriber buffer overflow
  • Choose Combine for new projects targeting iOS 13+, RxSwift for older version support

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