What is Combine and why is it needed?
Combine is an Apple framework for reactive programming, introduced in 2019 alongside iOS 13. It provides a declarative Swift API for processing events over time. Combine allows you to combine asynchronous event processing operators into data processing chains (pipelines).
The main task of Combine is to simplify working with asynchronous operations: network requests, notifications, KVO (Key-Value Observing), timers, delegates, and callback functions. Instead of disparate mechanisms, Combine offers a unified interface based on Publisher and Subscriber.
Key concepts:
- Publisher — a data source that can send values and complete (successfully or with an error).
- Subscriber — a data receiver that reacts to events from the Publisher.
- Operator — a method that transforms, filters, or combines data streams.
- Subscription — the connection between Publisher and Subscriber that manages the data flow.
Combine is tightly integrated with SwiftUI and Foundation, making it indispensable for modern iOS applications.
Installation
Combine is a built-in Apple framework. No additional packages need to be installed via CocoaPods, SPM, or Carthage to use it. It is available starting from iOS 13, macOS 10.15, tvOS 13, and watchOS 6.
To start using Combine, simply import it in a Swift file:
import CombineIf you use Swift Package Manager for dependency management, Combine is already included in the standard library. For projects supporting older OS versions, you can use OpenCombine — an open-source implementation of Combine.
Installing OpenCombine via SPM:
// In Package.swiftdependencies: [ .package(url: "https://github.com/CombineOpenSource/Combine.git", from: "0.5.0")]Quick start with a code example
Let's look at a simple example: creating a Publisher from an array and subscribing to it.
import Combine
// 1. Create a Publisher from an arraylet publisher = [1, 2, 3, 4, 5].publisher
// 2. Create a Subscriberlet subscriber = Subscribers.Sink<Int, Never>( receiveCompletion: { completion in print("Completed: \\(completion)") }, receiveValue: { value in print("Received value: \\(value)") })
// 3. Subscribepublisher.subscribe(subscriber)Console output:
Received value: 1Received value: 2Received value: 3Received value: 4Received value: 5Completed: finishedA more idiomatic way using the sink operator:
import Combine
let cancellable = [1, 2, 3, 4, 5].publisher .sink(receiveCompletion: { print($0) }, receiveValue: { print($0) })Note: sink returns an AnyCancellable. You need to keep a reference to it, otherwise the subscription will be cancelled immediately after leaving the scope.
Main methods/functions
1. sink(receiveCompletion:receiveValue:)
What it does: Creates a subscriber that receives all values and completion from the Publisher. This is the simplest way to subscribe to a stream.
Parameters:
receiveCompletion— a closure called upon completion (successful or with an error). AcceptsSubscribers.Completion<Failure>.receiveValue— a closure called upon receiving each new value.
Example:
let cancellable = Just("Hell