发布于 2026-01-06 0 阅读
0

RxSwift 6 有哪些新特性?

RxSwift 6 有哪些新特性?

祝大家2021年新年快乐!过去的一年非常艰难,我相信我们都希望新的一年会更好,我们最终能够恢复正常生活。

新年伊始,还有什么比发布新版本更好的呢?让我们一起来认识一下 RxSwift 6 吧

这篇博文将为您简要概述一些可能影响您的最值得注意的变化。

:这只是部分有趣的更改列表,显然不包括大量的较小错误修复和改进。

完整的变更日志请查看发行说明

事不宜迟,让我们直接进入正题吧!

目录

变化

新标志!

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

RxSwift 一直使用 Reactive Extensions 的原始 Volta Eel 标志,但我认为这次重大版本更新是一个很好的机会,可以为 RxSwift 的标志增添一些独特的元素。

这是一个让它拥有独特精神和身份的机会,同时还能向最初的 ReactiveX 标志和 Swift 的标志致敬。

隆重推出 RxSwift 的全新标志!

ezgif-2-d5c1852097c8

Binder从 RxCocoa 迁移到 RxSwift

这是一个虽小但呼声很高的改动,而且确实很合理。Binder顾名思义,它允许你定义一种将Observable流绑定到其中的方法,以便响应式地向该绑定的输入提供数据。

例如:

viewModel.isButtonEnable.bind(to: myButton.rx.isEnabled)
Enter fullscreen mode Exit fullscreen mode

使用底层接口Binder让你绑定到rx.isEnabled

Binder它一直存在于内部RxCocoa,但我们社区的用例和各种讨论表明,它是一个超级有用的实体,服务于更广泛的 RxSwift 用户,因此它现在是其中的一部分,并且不需要 RxCocoa 即可使用Binder

Binder使用自动合成@dynamicMemberLookup

RxSwift 包含一个名为 `ReactiveExtensions` 的命名空间.rx,允许你为特定对象添加自己的响应式扩展。

例如,假设有一个MyView如下所示的自定义设置:

class MyView: UIView { 
    var title: String
    var subtitle: String?
    var icon: UIImage?
}
Enter fullscreen mode Exit fullscreen mode

创建响应式绑定器的常见模式通常如下所示:

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
       }
    }
}
Enter fullscreen mode Exit fullscreen mode

这样就可以将适当类型的可观察流绑定到各种响应式输入:

viewModel.title.bind(to: myView.rx.title)
viewModel.subtitle.bind(to: myView.rx.subtitle)
viewModel.icon.drive(myView.rx.icon)
Enter fullscreen mode Exit fullscreen mode

这种方法效果很好,RxCocoa 本身也是通过这种方式为其用户提供反应性粘合剂的

不幸的是,这种代码也相当重复且冗余。它实际上只是镜像了底层对象Base的属性。

幸运的是,自 Swift 5.1 以来,我们有了更好的解决方案来解决这个问题—— @dynamicMemberLookup

RxSwift 6 会自动为任何类合成所有这些Binder元素,这意味着我上面展示的所有Binder代码都可以完全删除,从而真正地清理你的代码。

.rx只需在任何继承自该类的类上开始编写代码AnyObject,您就会立即看到为扩展基对象的每个属性自动合成的绑定器:

为 MyView 的所有属性自动合成粘合剂

不过不用担心,您自定义的响应式扩展仍然优先于合成的动态成员扩展,这使您可以进行更精细的控制。

withUnretained来到 RxSwift

在使用 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)
Enter fullscreen mode Exit fullscreen mode

注意:使用此操作符时,请谨慎使用缓冲操作符,因为share(replay: 1)它也会缓冲被保留的对象,这可能会导致循环引用。如果您需要更简单的替代方案,请查看subscribe(with:onNext:onError:onCompleted:onDisposed:)RxSwift 6.1 及更高版本

对于单个输出来说,这似乎没什么问题,但想象一下,在单个代码库中,这种情况会频繁出现。

幸运的是, 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)
Enter fullscreen mode Exit fullscreen mode

干净多了!

Infallible

Infallible是一种新型流,它与普通流完全相同,Observable只有一个区别——它保证不会失败。这意味着编译器保证你无法从中发出错误。

例如,你可以Observable.create使用以下方法创建一个类似的对象Infallible.create

Infallible<String>.create { observer in
    observer(.next("Hello"))
    observer(.next("World"))
    observer(.completed)
    // No way to error here

    return Disposables.create {
        // Clean-up
    }
}
Enter fullscreen mode Exit fullscreen mode

请注意,您只能传递 `a`.next(Element)或 ` .completedevent` 事件。您无法使此流失败。所有其他绕过此限制的操作符Infallible都具有相同的保证(例如,您不能调用 `as`Infallible.error而不是 `as` Observable.error)。

Driver如果你使用过 RxCocoa,你可能会想——嘿,这、和之间有什么区别Signal

首先,Infallible`observable` 存在于 RxSwift 中,而另外两个则存在于 RxCocoa 中。但更重要的是,` observable`Driver和`observable`Signal始终使用 `RxSwift`MainScheduler并共享资源(使用 ` share()RxCocoa`)。而 `Infallible` 则不然,它完全是一个基础的可观察对象,仅在编译时保证其绝对可靠。

decode(type:decoder:)运营商Observable<Data>

RxSwift 6 添加了一个专门用于发出 `eval` 的 `s` 的decode操作符,类似于`s`:ObservableDataCombine

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

可变drive()emit()

RxSwift 5 引入了可变参数(variadic)bind,它允许你执行以下操作:

viewModel.string.bind(to: input1, input2, input3)
Enter fullscreen mode Exit fullscreen mode

DriverRxSwift 6 现在为s 和s带来了相同的可变参数绑定Signal——使用可变参数driveandemit运算符:

viewModel.string.drive(input1, input2, input3)
viewModel.number.emit(input4, input5)
Enter fullscreen mode Exit fullscreen mode

Single现在更能效仿斯威夫特的做法Result

在 RxSwift 5 之前,Single有一个自定义事件:

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

如果你看着这个说,嘿——这看起来很像一个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)")
    }
)
Enter fullscreen mode Exit fullscreen mode

distinctUntilChange(at:)关键路径的新运算符

distinctUntilChanged是一个非常有用的运算符,它允许你丢弃相同值的排放,以避免浪费地处理它们。

例如:

myStream.distinctUntilChanged { $0.searchTerm == $1.searchTerm }
Enter fullscreen mode Exit fullscreen mode

键路径在这里又派上了用场。从 RxSwift 6 开始,你可以直接这样写:

myStream.distinctUntilChanged(at: \.searchTerm)
Enter fullscreen mode Exit fullscreen mode

新的ReplayRelay

中继会围绕主题进行封装,并允许你以只处理值的方式中继消息,因为中继保证永远不会失败或完成。

ReplayRelay是 RxSwift 6 的最新新增功能,它封装了ReplaySubject,此外还包括现有的BehaviorRelayPublishRelay

创建它使用的界面与创建ReplaySubject:

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

// Relay
ReplayRelay<Int>.create(bufferSize: 3)
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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

我们在 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:)
takeUntil(_:) take(until:)
observeOn(_:) observe(on:
subscribeOn(_:) subscribe(on:)

更好地支持 XCFrameworks

现在,每个 RxSwift 6 版本都会捆绑一组 XCFrameworks。

由于二进制模块的稳定性,升级到下一个 Swift 版本时,无需担心向前兼容性,即可轻松链接到预构建的 RxSwift 副本。

结束!

希望您喜欢这篇关于 RxSwift 6 一些最有趣的功能和更新的快速概述,但这并不是全部修复的问题。

本次更新包含大量错误修复、性能改进和新增功能,非常值得一试。请务必花点时间阅读更新说明

GitHub 标志 ReactiveX / RxSwift

Swift中的响应式编程

RxSwift 标志
构建状态 支持的平台:iOS、macOS、tvOS、watchOS 和 Linux

Rx 是通过接口表达的计算的通用抽象Observable<Element>,它允许您广播和订阅来自Observable流的值和其他事件。

RxSwift 是响应式扩展标准针对 Swift 的实现

RxSwift Observable 示例:价格不断变化并更新应用程序的 UI。

虽然此版本旨在忠实于 Rx 的原始精神和命名约定,但该项目也旨在为 Rx API 提供真正的 Swift 优先 API。

跨平台文档可在ReactiveX.io上找到

与其他 Rx 实现一样,RxSwift 的目的是以对象的形式轻松组合异步操作和数据流Observable,并提供一套方法来转换和组合这些异步工作片段。

KVO 观察、异步操作、UI 事件和其他数据流都被统一在序列抽象之下。这就是 Rx 如此简洁、优雅且强大的原因。

我来这里是因为我想

我们下篇博文再见,希望您喜欢 RxSwift 6!

文章来源:https://dev.to/freak4pc/what-s-new-in-rxswift-6-2nog