Articles about Swift and iOS Development by Natascha Fadeeva

Introduction to Combine for iOS developers with RxSwift experience

How to start using Combine for reactive programming

Image of the author.
Published 19. August 2019 - 4 min read

Everybody who used RxSwift or in general reactive programming concepts in their projects knows it's advantages. Doing async work in a unified way, composing asynchronious operations, avoiding callback hell, writing more clean and readable code are some of them.

Apple also recognized the benefits of reactive programming and introduced their new Combine framework at WWDC 2019. Although Apple is not using the word reactive programming in their official documentation, Combine can be described as a reactive framework. It offers iOS developers a unified declarative Swift API for processing values over time.

Key concepts of Combine

The key concepts of Combine are really similar to those of RxSwift. The namings are different though. So the first thing RxSwift developers will need to do is to get used to these new namings.

Oh my, so many namings! Let’s relax first.
Oh my, so many namings! Let’s relax first.

Publisher & Subscriber

A Publisher is what in RxSwift is an Observable. A publisher defines how values are produced and allows registration of a subscriber.

A Subscriber is what in RxSwift is an Observer. A subscriber receives values from the publisher after subscribing.

Let's remind how to create and subscribe to an Observable in RxSwift first:

let observable = Observable.from([1, 2, 3, 4])
observable.subscribe(onNext: { value in
}, onCompleted: {

And here how it looks to create and register to a Publisher in Combine:

let publisher = Publishers.Sequence<[Int], Error>(sequence: [1, 2, 3, 4])
publisher.sink(receiveCompletion: { _ in
}) { value in

Both examples produce the same output:



A SubjectType is what in RxSwift is a Subject, so the name is not that different in this case. Only the subtypes of a subject were named differently.

There are two kinds of a subject type in Combine: PassthroughSubject and CurrentValueSubject.

A PassthroughSubject is what in RxSwift is a PublishSubject. If you subscribe to it you will get all events that happen after you subscribed.

A CurrentValueSubject is what in RxSwift is a BehaviourSubject. It behaves like a PassthroughSubject but it also will send it's most recent element to new subscribers.

Let's remind how to create a subject and sending values to the observer in RxSwift:

let subject = PublishSubject<String>()
subject.asObservable().subscribe(onNext: { value in


And here the equivalent code in Combine:

let subject = PassthroughSubject<String, Never>()
subject.eraseToAnyPublisher().sink { value in

Both examples produce the same output:


If you like going deeper, you can find a good comparison of available RxSwift und Combine components here.


Many operators like map, flatMap, reduce etc. that are available in RxSwift are also available in Combine. Using Combine operators is just like using RxSwift operators.

So it should feel really familiar to see Combine operators in action:

Publishers.Sequence(sequence: [1, 2, 2, 3, 3, 4, 7])
    .map { $0 * 2 }
    .filter { $0.isMultiple(of: 2) }
    .sink { value in

This code produces the following output:


A full comparison list of RxSwift und Combine operators is available here.

Error Handling

A notable difference between RxSwift’s Observable and Combine’s Publisher is the error handling. In RxSwift, you always work with the general Error type, whereas in Combine you can use any kind of custom error. So when creating a publisher or a subject, the error type needs to be defined:

let publisher = Publishers.Sequence<[Int], SomeCustomError>(sequence: [1, 2])

Of course, you can also use the general Error type here. If there will be no error, you can use Never:

let subject = PassthroughSubject<String, Never>()

Memory Management

To deal with ARC and memory management, RxSwift provides a DisposeBag. In Combine you can use a collection of AnyCancellables.

Here is an example of how a DisposeBag is typically used in RxSwift:

let disposeBag = DisposeBag()
let subject = PublishSubject<String>()
subject.asObservable().subscribe(onNext: { value in
}).disposed(by: disposeBag)

And here is the equivalent example in Combine:

var cancellables = Set<AnyCancellable>()
let subject = PassthroughSubject<String, Never>()
subject.eraseToAnyPublisher().sink { value in
}.store(in: &cancellables)


I didn't compare the performance of RxSwift and Combine myself but there are some great articles about it. They all agree that Combine is clearly faster than RxSwift.

If you are interested in more specifics, you can find some performance tests and it's results here. The tests compare the performance of the most commonly used components and operators in RxSwift and Combine.


RxSwift is great and it's kind of sad by seeing it being replaced. But it is also great that reactive programming is now beeing pushed and supported by Apple.

There are some strong arguments for switching to Combine. Besides the fact of having one external dependency less, the performance lead is not neglectable. Combine also works greatly with SwiftUI, another new framework introduced at WWDC 2019.

The only reason, you might not want to switch to Combine right away is it's backward compatibility. Combine is supported only for iOS 13+. So if you need to support lower iOS versions, you may want to wait.

Written by

Image of the author.
Natascha Fadeeva
Author and creator of this site