In today’s article I’d like to give an introduction to Combine and show its main differences with RxSwift, and probably the best way to start is by showing Apple’s definition of Combine:

A unified, declarative API for processing values overtime

I’m sure it sounds familiar; that’s because, as we’ve said earlier, in this article we’ll talk about some of the similar features and differences between Combine and RxSwift, starting with Combine and its main features.

Combine vs RxSwift: Introduction to Combine

We’ll start by highlighting Combine’s three main attributes

  • Generic.
  • Type safe.
  • Composition first.

Apple tells us in their Combine keynote that the main concepts are simple and easy to understand, but once combined they allow for more complex and interesting stuff to be done.

Within Combine we’ll find:

  • Publishers
  • Subscribers
  • Operators

Publishers

Publishers are the most declarative part of Combine’s API. They define how values and errors are produced.
They’re Value type, in Swift, Structs.
Publishers allow the subscription of Subscribers, in turn letting us receive values once they’re emitted.

protocol Publishers {
    associatedtype Output
    associatedtype Failure: Error

    func subscribe<S: Subscriber>(_ subscriber: S) 
        where S.input == Output, S.Failure == Failure
}

Subscribers

Subscribers are the other side of the publishers coin. They receive values through the stream, and since these can mutate they are Reference types, like classes.

protocol Subscriber {
    associatedtype Input
    associatedtype Failure: Error

    func receive(subscription: Subscription)
    func receive(_ input: Input) -> Subscribers.Demand
    func receive(completion: Subscribers.Completion<Failure>)

}

This reminds me of something…

Looking at these basic Combine concepts we can deduce that it is very similar to other existing reactive programming frameworks like RxSwift or ReactiveCocoa. For now, let’s focus on how it compares to RxSwift.

If you’re familiar with RxSwift you’ll notice that Publishers are basically Observables and Subscribers are Observers; they have different names but work the same way. A Publisher exposes values that can change and a Subscriber “subscribes” so it can receive all these changes.

Combine vs RxSwift: Differences

Current compatibility

First off, Combine does not offer backward compatibility, that is, it’s not available for systems older than iOS 13 / macOS Catalina, since it needs the new runtime process in order to work. There are no future plans to introduce this backward compatibility.

RxSwift works with iOS 8 and above.

Error management

Looking at the specification for the Observable protocol we’ll spot the first differences.

In Combine, every Publisher needs to specify an error type, while in RxSwift, Observables don’t use an error type, instead they can throw any type of error at any given moment. This makes RxSwift’s Observables easier to use, since you don’t have to think about the types of errors that should be launched. On the other hand, this means you’ll have to be careful when managing errors by yourself, since the compiler won’t help you if you missed one, something that wouldn’t happen with Combine since it’s way more strict.

With Combine, if your stream doesn’t throw errors of any kind you can mark it with the type Never.

While this explicit specification of error types can be seen as an extra layer of security, it also adds some complications to the code. Meanwhile, you can get something similar with RxSwift using the Result type, which adds an additional error type but your stream wouldn’t stop after throwing an error, or using a specific stream for error management.

There’s another difference regarding error management: Combine separates functions as throwing or non-throwing. For example, there’re operators that have an error-throwing version and the non-throwing one.

Performance

Performance wise, and while it’s undeniable that RxSwift is a properly optimized framework, Combine has been built by Apple’s engineers with a 100% focus on performance.

As we can see on Flawless iOS blog, they did a comparison executing two code blocks doing the same work, one with Combine and the other with RxSwift, and we can observe that Combine’s time performance is the winner.

Alt Image Text

One of the main reasons for this improvement is because RxSwift uses Swift as its main language and thus needs to do a lot of sinks on the frameworks’ lower layers, affecting its performance. On the other hand, Combine is a Close Source project, and might not have necessarily been developed using Swift (but can expose a public Swift interface). Apple can use a lot of performance optimizations not available to developers outside of the company.

Operators

Combine and RxSwift have a lot of operators doing the same or a very similar job, but with a different naming.

Thankfully, the chart created by Shai Mishali can help us link all these operators with different names.

Open source

An important element that we’ve mentioned before is that Combine is not an open source project, something pretty logic if we take into account that the rest of Apple frameworks aren’t either. It’s feasible that Combine uses system features only available to Apple developers, but even if it was open source, Apple would still have a bigger advantage when tackling potential problems related to their core.

DisposeBag

You’re probably already familiar with RxSwift memory management pattern, DisposeBag. Instead of storing each subscription separately and ending them when the controller or class deinitializes, we simply write .disposed(by: disposeBag) and the framework will detect the deinit and get rid of all those Rx dependencies.

Combine doesn’t have anything similar to DisposeBag.

UI Framework

Inside a reactive framework we need some way to link the reactive flows to the view, and vice versa. RxSwift’s solution is RxCocoa.

Combine doesn’t have a specific framework to do these binds, instead we can use the assign method to link a stream to a key path and a view property.

publisher.assign(to: \.text, on: label)

Combine (still) doesn’t have a way to obtain a stream from a UI component in the same way we can with RxCocoa.

Conclusion

Mi opinion, leaving aside the differences between these frameworks, is that the creation of more reactive programming tools is very positive for Swift. It’s possible that the Combine’s emergence will give a popularity push to RxSwift, and during the next years, as Combine keeps maturing, at some point it might be worth it to jump straight into Apple’s framework. For the moment, and seeing how it has no backward compatibility, we can still enjoy RxSwift.