原文:What’s new in RxSwift 6 ?

新的 2021 年高兴!这是恰当艰难的一年,我相信咱们都期望有更好的一年,咱们总算能够过上正常的生活。

新年伊始,还有什么比发布新版别更好的工作呢?向 RxSwift 6 问好

这篇文章将向你快速概述一些或许影响你的最值得留意的变化。

留意:这仅仅一些风趣更新的部分列表,显然不包括很多较小的过错修正和改善。

有关完好的更改日志,请检查 release notes

话不多说,让咱们直接开端吧!

新 Logo

当然,这不是技术上的改动,但绝对值得一提。

RxSwift 一直运用 Reactive Extensions 的原始 Volta Eel 徽标,但我觉得这个主要版别或许是一个很好的机会,能够为 RxSwift 的徽标添加一些共同的优势。

这是一个以其自己的精神和身份使其绝无仅有的机会,一同依然尊重原始的 ReactiveX 徽标以及 Swift 的徽标。

我给你,新的 RxSwift Logo!

RxSwift 6 更新了什么

Binder 从 RxCocoa 迁移到 RxSwift

这是一个细小但强烈要求的改动,而且是有意义的。 Binder,顾名思义,答应你界说一种将 Observable 可调查序列绑定到其间的办法,以反响性地供给绑定的输入。

例如:

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

运用底层 Binder 让你绑定到 rx.isEnabled

Binder 一直存在于 RxCocoa 内部,但咱们社区的用例和各种讨论表明,它是一个超级有用的实体,能够为更广泛的 RxSwift 受众供给服务,因而它现在是其间的一部分,而且 RxCocoa 不需要运用 Binder。

运用 @dynamicMemberLookup 主动树立 Binders

RxSwift 包含一个名为 .rx 的命名空间,它答应你为特定目标放置自己的反响式扩展。

例如,给定一个如下所示的自界说 MyView

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

创建反响式绑定的常见模式一般如下所示:

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
       }
    }
}

这将答应你将恰当类型的可调查序列绑定到各种反响性输入:

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

这十分有用,甚至 RxCocoa 自身也是如此为其顾客供给响应式绑定的

不幸的是,这种代码也恰当重复和样板化。它真正所做的仅仅反映底层 Base 的属性。

幸运的是,从 Swift 5.1 开端,咱们针对这个问题有了更好的解决计划 ——@dynamicMemberLookup

RxSwift 6 将主动为任何类组成一切这些 Binder,这意味着我上面展现的一切 Binder 代码都能够彻底删去,并真正整理您的代码。

只需开端在任何 AnyObject 承继类上编写 .rx,你就会立即看到扩展根底目标的每个属性的主动组成绑定器:

RxSwift 6 更新了什么

不过不必忧虑,您自己的自界说反响式扩展依然优先于组成的动态成员扩展,这使您能够进行更精细的控制。

RxSwift 新增 withUnretained

运用 RxSwift 和 Cocoa /iOS 代码时的常见模式是获取对 self 的弱引用,以便您能够将宣布的值传递给一切者,例如:

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

留意:请当心将此运算符与缓冲运算符(例如 share(replay: 1))一同运用,因为它还会缓冲保留的目标,这或许会导致引用循环。如果您想要更简略的替代计划,请检查 RxSwift 6.1 中的 subscribe(with:onNext:onError:onCompleted:onDispose:)

关于单个输出来说,这似乎很好,但想象一下它在单个代码库中呈现的频率。

幸运的是,RxSwiftExt 是一个社区项目,它拥有不属于 RxSwift 自身的各种附加运算符,它有一个适合这种状况的运算符,称为 withUnretained。它最初是由一位好朋友、iOS 演讲者 Vincent Pradeilles 实现的。

因为该运算符的受欢迎程度以及该用例的普遍性,因而将其引进 RxSwift 自身是有意义的。

从 RxSwift 6 开端,您能够像这样重写上面的代码:

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

洁净多了!

Infallible

Infallible 是一种新型流,与 Observable 相同,只要一个差异 – 它确保不会失败。这意味着你不能从中宣布过错事情,这是由编译器确保的。

例如,您能够运用 Infallible.create 创建一个相似于 Observable.create 的目标:

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

请留意,您只能传递 .next(Element).completed 事情。你没有办法让这个可调查序列失败。一切其他环绕 Infallible 工作的运算符都具有相同的确保(例如,您不能调用 Infallible.error 而不是 Observable.error

如果您运用过 RxCocoa,您或许会想 — 嘿,DriverSignal 之间有什么差异?

首先,Infallible 坐落 RxSwift 中,而别的两个坐落 RxCocoa 中。但更重要的是,DriverSignal 一直运用 MainScheduler 并共享资源(运用 share())。 Infallible 的状况并非如此,它彻底是一个根底的可调查序列,仅具有编译时确保无误性的功用。

Observable<Data> 的新解码 (type:decoder:) 运算符

RxSwift 6 添加了一个解码运算符,专门用于宣布数据的 Observables,相似于兼并:

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

可变参数 drive()emit()

RxSwift 5 引进了可变参数绑定,它能够让您履行以下操作:

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

RxSwift 6 现在为 DriverSignal 带来了相同的可变参数绑定 – 运用可变参数驱动和宣布操作符:

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

Single 现在更好地遵从 Swift 的 Result

直到 RxSwift 5,Single 有一个自界说事情:

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

如果您看到这个并说,嘿 – 这看起来很像 Result<Element, Swift.Error>,那么你是对的!

从 RxSwift 6 开端,SingleEvent 仅仅 Result<Element, Swift.Error> 的别号。

这一变化也体现在其他 API 中,例如 subscribe

// 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)")
    }
)

支撑 keypath 的新的 uniqueUntilChange(at:) 运算符

uniqueUntilChanged 是一个超级有用的运算符,它能够让您删去相同的值排放以避免浪费地处理它们。

例如:

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

这是要害途径十分有用的另一种状况。从 RxSwift 6 开端,您能够简略地编写:

myStream.distinctUntilChanged(at: .searchTerm)

新的 ReplayRelay

Relay 环绕 Subject,让您以仅处理值的方式中继消息,因为中继确保永久不会失败或完结。

ReplayRelay 是 RxSwift 6 的最新弥补,除了现有的 BehaviorRelayPublishRelay 之外,它还包装了 ReplaySubject

创建一个运用与创建 ReplaySubject 彻底相同的接口

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

新的 DisposeBag 函数构建器

RxSwift 6 包含一个新的 DisposeBag 函数构建器,用于相似 SwiftUI 的无逗号语法:

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)
}

许多许多(许多)运算符重命名

咱们在 RxSwift 6 中花了一些时刻,重命名了许多运算符,以便尽或许更好地遵守 Swift 的代码攻略。

这是一个大部分完好的列表:

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:)
observeOn(_:) observe(on:)
subscribeOn(_:) subscribe(on:)

对 XCFrameworks 更好的支撑

RxSwift 6 的每个版别现在都会绑缚一组 XCFrameworks。

因为二进制模块的稳定性,这答应轻松链接到 RxSwift 的预构建副本,而无需忧虑升级到下一个版别的 Swift 时的前向兼容性。

总结

期望您喜欢 RxSwift 6 一些最风趣的功用和更新的快速概述,但这并不是一切问题都已修正。

有很多的过错修正、改善和小弥补值得一看。请必须花点时刻检查release notes