What's new in RxSwift 6 ?
Tags: ios, swift, rxswift, functional
Published: 2021-01-01 14:03:53

Happy new 2021! It's been quite a rough year, and I'm sure we're all hoping for a much better year where we'll finally be able to go to our normal lives.

To kick off the year, what's better than starting with a new release? [Say hello to RxSwift 6](https://github.com/ReactiveX/RxSwift/releases/tag/6.0.0).

This blog post will give you a quick rundown of some of the most note-worthy changes that might affect you.

> **Note**: This is just a partial list of some interesting changes, that obviously don't include a massive amount of smaller bug fixes and improvements.
>
> For the full change log, checkout the [release notes](https://github.com/ReactiveX/RxSwift/releases/tag/6.0.0).

Without further ado, let's just dive right in!

## Table of Content

- [New logo!](#new-logo)
- [`Binder` moves from RxCocoa to RxSwift](#-raw-binder-endraw-moves-from-rxcocoa-to-rxswift)
- [`withUnretained` comes to RxSwift](#-raw-withunretained-endraw-comes-to-rxswift)
- [Automatic synthesis of `Binder`s using `@dynamicMemberLookup`](#automatic-synthesis-of-raw-binder-endraw-s-using-raw-dynamicmemberlookup-endraw-)
- [`Infallible`](#-raw-infallible-endraw-)
- [New `decode(type:decoder:)` operator for `Observable<Data>`](#new-raw-decodetypedecoder-endraw-operator-for-raw-observableltdatagt-endraw-)
- [Variadic `drive()` and `emit()`](#variadic-raw-drive-endraw-and-raw-emit-endraw-)
- [`Single` now better follows Swift's `Result`](#-raw-single-endraw-now-better-follows-swifts-raw-result-endraw-)
- [New `distinctUntilChange(at:)` operator for Key Paths](#new-raw-distinctuntilchangeat-endraw-operator-for-key-paths)
- [New `ReplayRelay`](#new-raw-replayrelay-endraw-)
- [New `DisposeBag` function builder](#new-raw-disposebag-endraw-function-builder)
- [Many, many (many) operator renames](#many-many-many-operator-renames)
- [Better support for XCFrameworks](#better-support-for-xcframeworks)

## Changes

### New logo!

Not a technical change, for sure, but definitely one worth mentioning.

RxSwift always used Reactive Extensions' original Volta Eel logo, but I felt that this major release can be a great opportunity to add a bit of a unique edge to RxSwift's logo.

An opportunity to make it unique with its own spirit and identity, in a way that still gives honor to the original ReactiveX logo as well as Swift's logo.

I give you, the new RxSwift logo!

![ezgif-2-d5c1852097c8](https://dev-to-uploads.s3.amazonaws.com/i/xt6qirm3yfvnxyc5dhrd.gif) 

### `Binder` moves from RxCocoa to RxSwift

This is a small but highly requested change that just made sense. `Binder`, as the name suggests, lets you define a way to bind an `Observable` stream into it, to reactively feed that bound input.

For example:

```swift
viewModel.isButtonEnable.bind(to: myButton.rx.isEnabled)
```

Uses an underlying `Binder` to let you bind into `rx.isEnabled`

`Binder` always lived inside `RxCocoa`, but use-cases by our community and various discussions showed that it is a super useful entity that serves the broader RxSwift audience, so it is now part of it and RxCocoa isn't required to use `Binder`.

### Automatic synthesis of `Binder`s using `@dynamicMemberLookup`

RxSwift includes a namespace called `.rx` which lets you put your own Reactive Extensions on it for specific objects.

For example, given a custom `MyView` that looks like this:

```swift
class MyView: UIView { 
    var title: String
    var subtitle: String?
    var icon: UIImage?
}
```

A common pattern for creating reactive binders usually looks like this:

```swift
extension Reactive where Base: MyView {
    var title: Binder<String> {
       Binder(base) { base, title in 
           base.title = title
       }
    }

    var subtitle: Binder<String?> {
       Binder(base) { base, subtitle in 
           base.subtitle = subtitle
       }
    }

    var icon: Binder<UIImage?> {
       Binder(base) { base, icon in 
           base.icon = icon
       }
    }
}
```

This would let you bind an observable stream of the appropriate type to the various reactive inputs:

```swift
viewModel.title.bind(to: myView.rx.title)
viewModel.subtitle.bind(to: myView.rx.subtitle)
viewModel.icon.drive(myView.rx.icon)
```

This works great, and is even how [RxCocoa itself provides reactive binders for its consumers](https://github.com/ReactiveX/RxSwift/blob/5.1.0/RxCocoa/iOS/UILabel%2BRx.swift#L14-L30).

Unfortunately, this sort of code is also quite repetitive and boilerplate-y. All it _really_ does is mirror the underlying `Base`'s properties. 

Fortunately, since Swift 5.1, we have a better solution for this problem - [`@dynamicMemberLookup`](https://github.com/apple/swift-evolution/blob/master/proposals/0252-keypath-dynamic-member-lookup.md).

RxSwift 6 will **automatically synthesize all of these `Binder`s for any class**, which means that all of the `Binder` code I showed above can be entirely removed, and really clean up your code. 

Just start writing `.rx` on any `AnyObject`-inheriting class, and you'll immediately see automatically synthesized binders for every property of the extended base object:

![Automatically synthesized binders for all properties of MyView](https://dev-to-uploads.s3.amazonaws.com/i/fmifbl4wsgt2m2q8lvm8.jpg) 

Don't worry though, your own custom reactive extensions still take precedence over the synthesized dynamic member ones, which lets you have more granular control.

### `withUnretained` comes to RxSwift

A common pattern when working with RxSwift and Cocoa / iOS code is to get a weak reference to `self` so you could pass an emitted value to the owner, for example:

```swift
viewModel.importantInfo
    .subscribe(onNext: { [weak self] info in 
        guard let self = self else { return }
        self.doImportantTask(with: info)
    })
    .disposed(on: disposeBag)
```

> **Note**: Be careful using this operator with a buffering operator such as `share(replay: 1)` as it would also buffer the retained object, which might cause a retain cycle. If you want a simpler alternative to this, check out [`subscribe(with:onNext:onError:onCompleted:onDisposed:)` from RxSwift 6.1](https://docs.rxswift.org/protocols/observabletype#/s:7RxSwift14ObservableTypePAAE9subscribe4with6onNext0G5Error0G9Completed0G8DisposedAA10Disposable_pqd___yqd___7ElementQztcSgyqd___s0I0_ptcSgyqd__cSgAPtRld__ClF).

This might seem fine for a single output, but imagine how frequently this pops in a single code base. 

Luckily [RxSwiftExt](https://github.com/RxSwiftComunity/RxSwiftExt), a community project that holds various additional operators that aren't part of RxSwift itself, has an operator for this very case, called `withUnretained`. It was [initially implemented](https://github.com/RxSwiftCommunity/RxSwiftExt/pull/149) by a good friend and fellow iOS speaker, [Vincent Pradeilles](https://twitter.com/v_pradeilles).

Due to the popularity of this operator, and how common this use case is, it made sense to bring it into RxSwift itself. 

Starting with RxSwift 6, you can rewrite the above code like so: 

```swift
viewModel.importantInfo
  .withUnretained(self) // Tuple of (Object, Element)
  .subscribe(onNext: { owner, info in 
    owner.doImportantTask(with: info)
  })
  .disposed(by: disposeBag)
```

Much cleaner!

### `Infallible`

`Infallible` is a new type of stream that is identical to `Observable` with only one difference — it is guaranteed to not fail. This means you cannot emit errors from it, guaranteed by the compiler.

For example, you can create one similarly to `Observable.create`, using `Infallible.create`:

```swift
Infallible<String>.create { observer in
    observer(.next("Hello"))
    observer(.next("World"))
    observer(.completed)
    // No way to error here
    
    return Disposables.create {
        // Clean-up
    }
}
```

Note that you can only pass a `.next(Element)` or `.completed` event. There is no way for you to fail this stream. All other operators that work around `Infallible` have the same guarantee (for example, you cannot call `Infallible.error` as opposed to `Observable.error`)

If you worked with RxCocoa, you're probably thinking — hey, what's the difference between this, `Driver`, and `Signal`? 

First of all, `Infallible` lives inside RxSwift, while the other two live in RxCocoa. But more importantly, both `Driver` and `Signal` always use the `MainScheduler` and share their resources (using `share()`). This isn't the case with Infallible which is entirely a basic observable, only with compile-time guarantee for infallibility. 

### New `decode(type:decoder:)` operator for `Observable<Data>`

RxSwift 6 adds a `decode` operator that specifically works on `Observable`s that emit `Data`, similarly to `Combine`'s:

```swift
service.rx
       .fetchJSONUsers() // Observable<Data>
       .decode(type: [User].self, decoder: JSONDecoder()) // Observable<[User]>
```

### Variadic `drive()` and `emit()` 

RxSwift 5 introduced variadic `bind`, which lets you do:

```swift
viewModel.string.bind(to: input1, input2, input3)
```

RxSwift 6 now brings the same variadic binding for `Driver`s and `Signal`s - using variadic `drive` and `emit` operators:

```swift
viewModel.string.drive(input1, input2, input3)
viewModel.number.emit(input4, input5)
```

### `Single` now better follows Swift's `Result`

Up until RxSwift 5, `Single` had a custom event: 

```swift
public enum SingleEvent<Element> {
    case success(Element)
    case error(Swift.Error)
}
```

If you're looking at this and saying, hey - this looks a lot like a `Result<Element, Swift.Error>`, you're absolutely right!

Starting with RxSwift 6, `SingleEvent` is simply an alias for `Result<Element, Swift.Error>`. 

This change is also reflected in other APIs such as `subscribe`:

```swift
// RxSwift 5
single.subscribe(
    onSuccess: { value in
        print("Got a value: \(value)")
    },
    onError: { error in
        print("Something went wrong: \(error)")
    }
)

// RxSwift 6
single.subscribe(
    onSuccess: { value in
        print("Got a value: \(value)")
    },
    onFailure: { error in
        print("Something went wrong: \(error)")
    }
)
```

### New `distinctUntilChange(at:)` operator for Key Paths

`distinctUntilChanged` is a super useful operator which lets you drop identical value emissions to avoid wastefully processing them.

For example:

```swift
myStream.distinctUntilChanged { $0.searchTerm == $1.searchTerm }
```

This is another case where Key Paths can prove quite useful. Starting with RxSwift 6, you can simply write:

```swift
myStream.distinctUntilChanged(at: \.searchTerm)
```

### New `ReplayRelay`

Relays wrap around subjects, and let you relay messages in a way that only handles values, since relays are guaranteed to never fail or complete.

`ReplayRelay` is the latest addition to RxSwift 6, which wraps `ReplaySubject`, in addition to the existing `BehaviorRelay` and `PublishRelay`.

Creating one uses the exact same interface as creating a `ReplaySubject`:

```swift
// Subject
ReplaySubject<Int>.create(bufferSize: 3)

// Relay
ReplayRelay<Int>.create(bufferSize: 3)
```

### New `DisposeBag` function builder

RxSwift 6 includes a new `DisposeBag` function builder for SwiftUI-like, comma-less syntax:

```swift
var disposeBag = DisposeBag { 
    observable1.bind(to: input1)

    observable2.drive(input2)

    observable3.subscribe(onNext: { val in 
        print("Got \(val)")
    })
}

// Also works for insertions
disposeBag.insert {
    observable4.subscribe()
    
    observable5.bind(to: input5)
}
```

### Many, many (many) operator renames

We took the time in RxSwift 6 and renamed many operators to better respect Swift's code guidelines where possible.

Here is a mostly complete list:

**RxSwift 5**|**RxSwift 6**
:-----:|:-----:
`catchError(_:)`|`catch(_:)`
`catchErrorJustReturn(_:)`|`catchAndReturn(_:)`
`elementAt(_:)`|`element(at:)`
`retryWhen(_:)`|`retry(when:)`
`takeUntil(_:)`|`take(until:`)
`takeUntil(behavior:_:)`|`take(until:behavior:)`
`takeWhile(_:)`|`take(while:`)
`takeWhile(behavior:_:)`|`take(while:behavior:)`
`take(.seconds(3))`|`take(for: .seconds(3)`)
`skipWhile(_:)`|`skip(while:)`
`takeUntil(_:)`|`take(until:)`
`observeOn(_:) `|`observe(on:`)
`subscribeOn(_:)`|`subscribe(on:)`

### Better support for XCFrameworks

Every release of RxSwift 6 will now have a set of XCFrameworks bundled with the release. 

This allows easily linking against a prebuilt copy of RxSwift without worrying about forward compatibility when upgrading to the next version of Swift, thanks to binary module stability.

## Wrapping up!

Hope you've enjoyed this quick rundown of some of the most interesting features and updates to RxSwift 6, but it's not all that was fixed.

There are a _ton_ of bug fixes, improvements and small additions that are worth checking out. Be sure to take a moment to review the [release notes](https://github.com/ReactiveX/RxSwift/releases/tag/6.0.0).

{% github https://github.com/ReactiveX/RxSwift %}

See you on the next blog post, and hope you enjoy RxSwift 6!