What’s new in RxSwift 5
Learn about the newest additions to RxSwift
RxSwift 5 was finally released just a few days ago, and I thought this would be a great opportunity to share a quick list of the most note-worthy changes pushed into this release.
No worries though, as this release is mostly source-compatible with only a few deprecations and renames. But it also packs a bunch of underlying improvements I’ll detail below.
Relays are now a separate framework — RxRelay
Relays are a great abstraction layer on top of Subjects that lets you relay elements without worrying about errors or completion events. Since they were added to RxSwift, they lived as part of the RxCocoa project.
Some developers were unhappy with this, since it meant RxCocoa must be imported to use Relays even on code layers where it didn’t necessarily make sense. It also made it impossible to use Relays under Linux, where RxCocoa can’t be used.
For the reasons above, we’ve moved Relays into their own framework — RxRelay — and adjusted RxSwift’s dependency graph as follows:
This lets you use RxSwift and RxRelay only, without depending on RxCocoa if you don’t need it, and also aligns with RxJava where it’s a separate framework.
Note: This is a backward compatible change, since RxCocoa imports RxRelay directly. Meaning, you can keep importing RxCocoa without also importing RxRelay and everything will work as it did before.
TimeInterval → DispatchTimeInterval
Schedulers have been refactored in RxSwift 5 to deprecate the usage of TimeInterval
in favor of DispatchTimeInterval
. This allows for better granularity of event scheduling and higher stability when sub-second timings are needed.
This affects all time-based operators such as throttle
, timeout
, delay
, take
etc. As a fortunate side-effect, this disambiguates take
, where it wasn’t obvious if a developer refers to seconds or number of elements.
RxSwift 4.x:
RxSwift 5.x:
Variable is finally deprecated
Variable
is a concept added into RxSwift in its early days which basically let you create an imperative bridge by “setting” and “getting” a current value to and from it. It was a seemingly helpful measure to get developers started with RxSwift until they fully understand “Reactive Thinking”.
This construct proved to be problematic as it was heavily abused by developers to create highly-imperative systems instead of using Rx’s declarative nature. This was especially common with beginners to Reactive Programming and conceptually prevented many from understanding this is a bad practice and a code smell. This is why Variable
was soft-deprecated with a runtime warning, already in RxSwift 4.x.
In RxSwift 5, It is now officially and completely deprecated, and the recommended approach is to use BehaviorRelay
(or BehaviorSubject
) instead if you need this sort of behavior.
RxSwift 4.x:
RxSwift 5.x:
Additional do(on:)
overloads
do
is a great operator to use when you want to perform some side-effect such as logging, or simply “listen in” the middle of your stream.
To align with RxJava, RxSwift now offers not only do(onNext:)
but also after overloads, such as do(afterNext:)
. onNext
represents the moment the element has been emitted, whereas afterNext
represents the moment after
it has been emitted and pushed downstream.
RxSwift 4.x:
RxSwift 5.x:
bind(to:) now supports multiple observers
There are scenarios where you have to bind a stream to multiple observers. In RxSwift 4, you would usually simply duplicate the binding code:
RxSwift 5 now supports binding to multiple observers:
This still resolves to a single Disposable
, which means it’s backward compatible with the single-observer variation.
A new compactMap operator
As developers, you often deal with streams of Optional
values. To unwrap these values, the community has had its own solutions to it, such as the unwrap
operator from RxSwiftExt or filterNil
from RxOptional.
RxSwift 5 adds a new compactMap
operator to align with the Swift Standard Library, bringing this ability into the core library.
RxSwift 4.x:
RxSwift 5.x:
toArray() now returns Single<T>
toArray()
is an operator that emits the entire stream as an array once the stream completes.
Since the inception of RxSwift, this operator always returned an Observable<T>
, but due to the introduction of Traits — specifically, Single
, it made sense to change the return type to Single<T>
to provide that type safety and guarantee of only getting a single emitted value from this operator.
RxSwift 4.x:
RxSwift 5.x:
Generic constraints naming overhaul
RxSwift is a heavy consumer of generic constraints. Since its early days, the library used single-letter constraints to describe certain types. For example, ObservableType.E
represents the generic type of the Observable stream.
This works fine but causes some confusion with constraints such as O
which represents both Observable
and Observer
in different scenarios, or S
which represents Subject
and Sequence
.
Furthermore, these single-letter constraints weren’t providing good self-documenting code and made it hard for non-contributors to understand the references.
For these reasons we’ve overhauled most generic constraints for both private and public interfaces to be more informational and verbose.
The most widely impacting rename is E
and ElementType
to simply Element
.
RxSwift 4.x:
RxSwift 5.x:
The generic renames were quite extensive. Here’s a mostly-complete list of them. Most of these changes relate to the internal APIs of RxSwift, and only a few of these would affect you as developers:
E
andElementType
were renamed toElement
.TraitType
was renamed toTrait
.SharedSequence.S
was renamed toSharedSequence.SharingStrategy
.O
was renamed toObserver
andSource
wherever applicable.C
andS
were renamed toCollection
andSequence
, respectively.S
was also renamed toSubject
where applicable.R
was renamed toResult
.ReactiveCompatible.CompatibleType
was renamed toReactiveCompatible.ReactiveBase
.
Community Projects
Many RxSwift Community projects already migrated to RxSwift 5 and released appropriate versions, so the migration process should be relatively smooth. Some of the projects that already migrated are: RxSwiftExt, RxDataSources, RxAlamofire, RxOptional, and more.
Wrapping up
The changes listed above are the majority of developer-facing changes, but there are many more smaller fixes that are out-of-scope for this sort of post such as fully fixing compatibility with Swift 5 under Linux, minor anomalies, etc.
Feel free to check out the full Change Log and participate in the discussions in the official repository: https://github.com/ReactiveX/RxSwift
Hope you’ve enjoyed this post :-)
Got any questions? Feel free to share them below, in the comments section.