Will Combine kill RxSwift?

Anton Nazarov
Jun 12, 2019 · 11 min read

Combine framework was presented at WWDC2019. This is an obvious competitor to RxSwift, which implements the reactive streams specification. Let’s talk about whether something changed in our lives.

Yes, it is beta. Design, performance, API can change to the worse or to the better side. But many things are already obvious.

My article will contain many clickable links (this is not an advertisement), because, in fact, everything was already said. It remains only to put things together in a nice order. Today we will go through:

Table of Contents

When you are so tired of explaining who is the only king here

Backpressure

Historically, RxSwift does not support backpressure. There is no separation between Flowable and Observable like it has been done in RxJava. This is a resolved question that will not be revised in the foreseeable future. You can read more about the reasons here:

To solve this problem, RxSwift has a useful set of operators and basic runtime check on Reentrancy anomaly, which is absolutely enough to provide comfortable bug-free development.

Combine supports backpressure out of the box. The receive method should return the number of items that the subscriber wants to accept. If you don’t care, just return Demand.unlimited.

This is cool, I guess. But I have written a lot of RxSwift code and I didn’t meet any case where I would need backpressure support. I can always solve it with the available operators set.

Typed Errors

This a very hot question that pops up every time discussion comes to reactive streams. Should the error be typed or is it just an Error? RxSwift believes that Error is enough. You can read the latest folks’ discussion about that stuff here.

Combine has it out of the box. You have to provide Publisher error type. There are also few operators to work with errors. You can map it, replace it, handle as usual next event.

Honestly, I do not know why do we need an explicit error type. For most cases, we work with errors as something abstract. We have some generic pop-up where our favorite “Something went wrong…” is placed. Otherwise, we do not want to handle errors and prefer to show the usual empty screen or error state. I am a big fan of error handling as a separate stream and very rarely work with a specific type. In our project, there is no custom type that conforms to Swift.Error.

Exceptions handling

I don’t know why, but Combine split throwing/not throwing operators. For instance, if your map closure might throw you should apply it through tryMap.

Is that good? I would say, as a developer, I don’t care. I prefer RxSwift way with throwing closures by default. You will not use that try(map|filter|scan) in some specific way. You just don’t need that logic. Because, honestly, developers don’t like errors and don’t know what to do with them.

DisposeBag

DisposeBag is RxSwift memory management pattern. Instead of saving each subscription separately and terminating it, you simply write .disposed(by: disposeBag) and get one variable that is responsible for all subscriptions disposing. Normal behavior is disposing in deinit, when disposeBag reference counter becomes zero. You expect this behavior by default.

However, this and the absence of garbage collector also introduces the global problem of the reference cycle, which an inexperienced user can easily meet. Of course, there are many ways to control this; you can even write tests on the correct handling of reference cycles. I will show a more detailed way to prevent memory leaks in the next article, subscribe not to miss.

There is nothing similar to DisposeBag in Combine. There is a Cancellable (bring me back my Disposable) which you can cancel and release all resources. However, working with Cancellable in ARC might be quite confusing. Here is a great article which shows Combine problems with examples.

I’m a big fan of DisposeBag. It is convenient and very simple. For instance, there is a widely known pattern to clear subscriptions in cells:

final class Cell: UITableViewCell {
private var disposeBag = DisposeBag()
func prepareForReuse() {
super.prepareForReuse()
disposeBag = DisposeBag()
}
...
}

I have seven subscriptions in the largest cell in the current project. Perhaps I don’t really want to write this cleanup code for each of seven Cancellable. It seems to me that it would be logical to add a similar type CancelBag, but Apple engineers know their stuff better than me. Therefore, it remains only to wait, fingers crossed. In extreme cases, you can easily provide your custom implementation.

API

RxSwift vs Combine is not equal to Kotlin coroutines vs RxJava problem. Tools which can be used to handle similar problems and similar tools are not the same. API is totally equal. Yes, words may differ slightly, but these are the same framework, written in different ways. If you are interested in more details — here is a comparison of RxSwift and Combine API from the awesome Shai Mishali, of one of the main RxSwift maintainers.

Yes, there are no flatMapLatest or usual traits like Maybe, Completable orDriver. But it’s just implementation details. For Apple they are… not necessary. I have not encountered any problems with their absence while experimenting with SwiftUI + Combine.

BTW SwiftUI will kick your ass

RxSwift is not going to just copy all Combine API. But I am going to silently steal operators that make sense and applicability. For instance, here is a cool assign operator that is already being added to RxSwift. Do not hesitate, RxSwift will be as comfortable as Combine to use. If you are interested in having your favorite Combine operators in RxSwift, take a part in this issue. Just vote, and I will implement everything for you.

Performance

I would like to say that RxSwift is as fast as Combine. But I can’t lie to you. Here is a small test case that just applies meaningless operators. That’s how we usually program it, right?

Oh boy

The results are disappointing. Yes, we rarely filter millions of items streams, but nevertheless:

RxSwift vs Combine time

Sadly I have no extra 6 thousands of dollars for new Mac Pro, so just 10 millions of elements. This ratio grows linearly. I will not attach charts for a different number of elements, but you can copypaste this test and run it by yourself.

RxSwift vs Combine allocations (KBs)

It is no secret that RxSwift initiates many sinks under the hood. It’s just designed like that and I doubt that someone would easily have a better solution. However, Combine was designed for a long time with an emphasis on performance. And it’s not just words.

Well… It’s good. Obviously, developers from Apple who have no barriers and have all the sources in their hands can do better than community. Honestly, I did not think it could be SO MUCH better 😅. A cool boost of performance is always good, but… Try to remember when was the last time you used XCTestCase.measure? I strongly doubt that your tableView scrolls not fast enough only because of RxSwift.

Sugar

You can agree or not, but RxSwift and Combine are really the same frameworks. Combine is implemented entirely in modern Swift, so you can use its protocols and provide custom implementations of Publishers. But you are not going to write your own Map, are you? Therefore, I have no comments on that change. Openness for expansion is good. But this openness allows developers to write crutches and make mistakes, not respecting the contract. The framework should deliver everything you need out of the box and not allow the user to change the rules or reinvent wheels.

Value for the industry

There will always be skeptics. Skeptics tried to convince us that computer is not suitable for the simple user and iPhone is impossible. Skeptics said that Swift is a toy just to attract new developers, and Apple will continue to write in ObjC. There always have been skeptics who said that reactive programming is dark magic and there is nothing better than the good old delegate-pattern.

Now the community is excited and everyone loves SwiftUI. But just a few people think about reactivity, which is, in fact, the core feature of the new way of implementing applications. You decide, but I would say it’s… quite important.

Is this a defeat for RxSwift? No, it is a victory for Apple. A lot of people have already paid attention to the fact that it was the brightest WWDC for developers for a long time. SwiftUI is absolutely cool. Apple needs to regain its position in the market after unsatisfactory sales of latest iPhones. They analyzed community requests and did everything to cajole developers. They tried to make every developer in the world wanted to write an application for Apple. And honestly, they did it.

And here it is. Reactive programming. It should be said that RxSwift is not very popular in iOS development. While Android app just can’t be implemented without RxJava, we (iOSers) still doubt should we try this lib. “This is a third party” and “Too complicated, magic in your code” became really popular arguments against RxSwift. And now Apple is announcing a reactive framework, just meaning “Yes, guys. This is the future of iOS development. Now it’s official. Deal with it” Obviously, now many more developers will change delegates to Rx. And if they aren’t… they should be.

iOS 13.0 +

Combine is not allowed for lower iOS version. What can you do with that?

RxSwift is a good alternative for reactive programming right now. You do not need to support iOS 13.0+ to program reactively. I guess you might saw new stuff from Apple. I am surprised that folks just like: “Wow, one method to set up a table view, it’s so convenient, so modern.” Apple did not invent anything new as usual, they just made the old better. You can configure your tables with one line right now for lower iOS versions (I have been using it for two years):

It is noteworthy that a framework for reactive programming formed a huge number of convenient extensions around itself. Reactivity has become a synonym for conciseness for me. You can read about the convenience of RxSwift in my previous article.

reactivity is dangerous (sorry, with all respect)

RxSwift community is really awesome. Cause reactivity is not just a way to handle asynchronous events, but a way to think, design your application. Declarativity, unidirectionality, stateless components… You can use all these features right now. Something similar you will have to use with SwiftUI. You know all that BLoC stuff from Flutter.

What’s next?

I would really like to say that RxSwift will live forever and someday I will explain it to my son. But this is not true. RxSwift will be dead in a few years. This is not just hype words, but it’s a fact. You can read more here. The most particularly interesting is the comment of Krunoslav Zaher, the man who made iOS developers’ life much happier.

You can interpret it as you wish, but for me, this is a sad goodbye. It was a great job and I wish I was born earlier to stand at the origins of this repository. I have done too little for it, trying to catch up now. We work hard to provide users, who are interested in Combine, a more pleasant RxSwift experience. New Combine-like operators coming soon.

But all this is just a pursuit for a dream. RxSwiftCommunity can add any extensions to UIKit. But, unfortunately, we will never be able to contribute directly to Apple frameworks. Combine looks like a durable feature. Apple supports it in RealityKit, SwiftUI uses it under the hood. This is logical. RxSwift can never become something more than just a third party that you use to make development easier.

The correct question would be not “should I use Combine?”, but “when exactly should I start to do this?”. It depends on your requirements. For example, in the current project, my team support only iOS 12, therefore, we will probably soon migrate to SwiftUI + Combine stack. This is the future, guys, and the only question is “how soon you will be ready to drop your legacy and go into a brave new world?”. Nobody forces you, but it is necessary. Just to prevent your developers fall into depression.

Opensource

“Why they don’t opensource Combine?” became a really popular question, which is strange for me. Just because all other Apple frameworks are not opensourced. They probably use features, which are not allowed to simple users. They don’t want to resolve issues, review contributors PRs. Cause they can handle that better than anyone else. And that’s it, I don’t want any other reasons to agree with that policy.

Subjective

Sorry but Publisher is a really bad name. We have a Gang of four book with well-known Observable pattern. We have great Eric Meyer and after all, you call it Publisher? Of course, I will get used to it, but… in Russian, Publisher translates as “he” and Observable like “it”. What about diversity, Apple?

Also, RxSwift supports dark mode out of the box, which I can’t say about Combine. Your choice.

My plans

First of all, I am going to drink some beer for the good life of RxSwift. I am going to give a few tech talks about RxSwift vs Combine. Honestly, I just want people to understand what they hold in their hands. Not just shout out words like gorgeous, amazing or exciting, but really understand why this is… exciting. It’s not just a feature, it’s a new age of iOS development. I bet for Combine and SwiftUI and advise you to do the same.

Me talking about RxSwift in 2026

After 10 years, I plan to be an old man who tells everyone about how we used RxSwift. And, damn it, it was awesome.

References

So, there are many of them above. Just check out that.

Interesting thread about Combine from RxSwift maintainer

If you enjoyed my opinion, please give it a clap (50) and share to help others find it! Feel free to leave a comment below. Follow me to read more about Rx. Twitter: M0rtyMerr

Archived — Flawless iOS

Archive of Flawless iOS publication — no longer accepting submissions