DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Coding
  3. Frameworks
  4. RxSwift vs. ReactiveSwift

RxSwift vs. ReactiveSwift

Some of the most common use cases for reactive programming are asynchronous networking and binding values to UI controls. Is RxSwift or ReactiveSwift better at handling them?

Adam Sharp user avatar by
Adam Sharp
·
Feb. 07, 17 · Opinion
Like (1)
Save
Tweet
Share
9.35K Views

Join the DZone community and get the full member experience.

Join For Free

In June 2016, Chris Eidhof and Florian Kugler (of objc.io fame) started a new Swift screencast series called Swift Talk. The format is simple: for 15 to 20 minutes each week, two experienced programmers pair-program, problem-solve and refactor together. The result is some excellent insight into the process of programming and design.

Last week in episode #34, Chris and Florian did their first episode on one of my favorite topics: Reactive Programming. They work through a reactive programming problem using RxSwift, exploring some of the most common use cases for a reactive programming library: asynchronous networking, combining event streams from multiple sources, and binding values to UI controls. The source code for the episode is available for free on GitHub. Whether or not you’ve watched the episode, I recommend cloning the repo and playing around with the app in the simulator.

I haven’t yet had the opportunity to work with RxSwift, but I have a lot of experience with ReactiveCocoa and have made a few contributions. Since the recent release of ReactiveCocoa 5, which overhauled its UI binding APIs for Swift 3, and ReactiveSwift (the cross-platform core of ReactiveCocoa), I thought it would be interesting to use this example app from Swift Talk to compare the two libraries.

A quick note on terminology: throughout this article, I’ll be using RxSwift to also refer to RxCocoa, which is bundled alongside it and provides the UI binding layer. In the same way, I’ll be using ReactiveSwift and ReactiveCocoa interchangeably.

Porting From RxSwift to ReactiveSwift

Let’s take a first pass and port examples in the source directly to the equivalent ReactiveSwift APIs. Even though the changes are fairly minimal, we can learn a lot about the philosophical differences between the two libraries.

Observing Changes to a Simple UI Control

-let priceSignal = priceSlider.rx.value
+let priceSignal = priceSlider.reactive.values
     .map { floor(Double($0)) }

-priceSignal
+priceLabel.reactive.text <~ priceSignal
     .map { "\($0) USD" }
-    .bindTo(priceLabel.rx.text)
-    .addDisposableTo(disposeBag)

Here's the original source.

RxSwift’s bindTo(_:) and addDisposableTo(_:) functions are both unified in ReactiveSwift under the binding operator, <~. On the left side of the operator is the “binding target”, defined by BindingTargetProtocol. Binding targets do two things: consume values from a stream, and define a Lifetime, i.e., when the binding should end (usually when the target is deinitialized).

-func load<A>(_ resource: Resource<A>) -> Observable<A> {
-    return Observable.create { observer in
+func load<A>(_ resource: Resource<A>) -> SignalProducer<A, AnyError> {
+    return SignalProducer { observer, disposable in
         print("start loading")
         self.load(resource) { result in
             sleep(1)
             switch result {
             case .error(let error):
-                observer.onError(error)
+                observer.send(error: AnyError(error))
             case .success(let value):
-                observer.onNext(value)
-                observer.onCompleted()
+                observer.send(value: value)
+                observer.sendCompleted()
             }
         }
-        return Disposables.create()
     }
 }

Here's the original source.

The biggest difference here is the SignalProducer type. Here’s where ReactiveSwift begins to diverge from RxSwift: the notion of “hot” and “cold” signals are separated out into two different types. You can compare RxSwift’s explanation of the difference with ReactiveSwift’s TV streaming analogy.

The second major difference between the two libraries is ReactiveSwift’s Signal and SignalProducer add a second generic type parameter: the Error type. If you’re familiar with Swift’s error handling model, it might seem like an unconventional choice to have strongly-typed errors. One benefit is that errors can become self-documenting: you have a type whose documentation or source code can be looked up to discover what errors might occur. But the real benefit is the existence of the NoError type, which allows you to prove at compile time that no ever will ever occur, by being impossible to construct. Many of ReactiveSwift’s error handling features are made possible by NoError.

In this case, because we’re bridging untyped Swift errors into the strongly-typed model of ReactiveSwift, we use the AnyError wrapper type.

Combining the Results

-let vatSignal = countriesDataSource.selectedIndex.asObservable()
-    .distinctUntilChanged()
+let vatSignal = countriesDataSource.selectedIndex.producer
+    .skipRepeats()
     .map { [unowned self] index in
         self.countriesDataSource.countries[index].lowercased()
-    }.flatMap { [unowned self] country in
-        self.webservice.load(vat(country: country)).map { Optional.some($0) }.startWith(nil)
-    }.shareReplay(1)
+    }.flatMap(.latest) { [unowned self] country in
+        self.webservice.load(vat(country: country)).map { Optional.some($0) }.prefix(value: nil)
+    }.replayLazily(upTo: 1)

Here's the original source.

There’s a little more going on here:

  • countriesDataSource.selectedIndex has changed from a Variable<Int> to a MutableProperty<Int>. To observe the current value, followed by all future changes, we use the producer property, which returns a SignalProducer<Int, NoError>.
  • There’s a new .latest parameter to flatMap(). You can learn about the differences between flattening strategies in ReactiveSwift’s documentation. These strategies are all possible in RxSwift, but the flatMap operator chooses a default strategy. In ReactiveSwift, no strategy is considered to be a sensible default for all cases, and so you instead choose the strategy that is most appropriate for your use case.
  • The shareReply() operator is basically the same, but under the name replayLazily(upTo:).

RxSwift provides the Variable type, a mutable box that holds a current value and lets you observe changes to its value over time. In order to combine Variables with other streams, you have to convert it to an Observable, losing its “Variable-ness” in the process. ReactiveSwift’s MutableProperty is equivalent, but along with PropertyProtocol, there are a number of interesting ways you can combine properties, while preserving the fact that a) they are guaranteed to have a current value, and b) they are guaranteed to never fail. You can read more about Property in ReactiveSwift’s documentation.

RxSwift and ReactiveSwift are two different approaches — perhaps surprisingly so — to the same underlying problem. Both make heavy use of Swift’s type system to help you describe your application’s asynchronous logic in a high-level way, and with very different results.

This episode of Swift Talk was an introduction to reactive programming, and not intended to prescribe the “right way” of solving the problem. There’s certainly a more idiomatic way to write this code with either library. By comparing these two libraries, we’ve been able to see how even apparently subtle differences in API design can influence the code we write.

Swift (programming language)

Published at DZone with permission of Adam Sharp, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • gRPC on the Client Side
  • What Are the Different Types of API Testing?
  • Cloud Performance Engineering
  • Java Concurrency: LockSupport

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: