Combine 会杀死 RxSwift 吗?

原文:Will Combine kill RxSwift?

WWDC2019 推出了 Combine 框架。这是 RxSwift 的明显竞争对手,RxSwift 实现了反应式流规范。让我们谈谈我们的生活是否发生了变化。

是的,它是 beta 版。设计、性能、API 可能会变得更糟或更好。但很多事情已经很明显了

我的文章将包含许多可点击的链接(这不是广告),因为事实上一切都已经说过了。剩下的只是将事物按照良好的顺序组合在一起。今天我们将预览:

TOC

Backpressure(背压?)

如何处理 Observables 产生元素的速度比观察者消耗它们的速度快的问题?

从历史上看,RxSwift 不支持 backpressure。 Flowable 和 Observable 之间没有像 RxJava 中那样进行分离。这是一个已解决的问题,在可预见的将来不会修改。您可以在此处阅读有关原因的更多信息:

为了解决这个问题,RxSwift 有一组有用的运算符和对重入异常的基本运行时检查,这绝对足以提供舒适的无错误开发。

Combine 支持开箱即用的背压。receive 方法应返回订阅者想要接受的元素数。如果你不在乎,只需返回 Demand.unlimited 即可。

我想这很酷。但我已经编写了很多 RxSwift 代码,并且没有遇到任何需要背压支持的情况。我总是可以使用可用的运算符集来解决它。

类型错误

这是一个非常热门的问题,每次讨论反应式流时都会出现。应该输入错误还是只是一个 Error? RxSwift 认为 Error 就足够了。你可以在这里阅读人们关于这些内容的最新讨论

Combine 开箱即用。你必须提供 Publisher 错误类型。也很少有操作符能够处理错误。您可以映射它、替换它、照常处理下一个事件。

老实说,我不知道为什么我们需要一个明确的错误类型。在大多数情况下,我们将错误视为抽象的东西。我们有一些通用的弹出窗口,其中放置了我们最喜欢的 "Something went wrong..."。否则,我们不想处理错误,而是更喜欢显示通常的空屏幕或错误状态。我非常喜欢将错误处理作为单独的流,并且很少使用特定类型。在我们的项目中,没有符合 Swift.Error 的自定义类型。

异常处理

我不知道为什么,但是 Combine 拆分了 throwing/not throwing 运算符。例如,如果你的 map 闭包可能会抛出异常,你应该通过 tryMap 应用它

这样好吗?我想说,作为一名开发人员,我不在乎。我更喜欢默认抛出闭包的 RxSwift 方式。你不会以某种特定方式使用 try(map|filter|scan) 。你只是不需要那个逻辑。因为,老实说,开发人员不喜欢错误,也不知道如何处理错误。

DisposeBag

DisposeBagRxSwift 内存管理模式。您无需单独保存每个订阅并终止它,只需编写 .dispose(by: disposeBag) 并获取一个负责所有订阅处置的变量即可。当 disposeBag 引用计数变为零时,正常行为是在 deinit 中进行处理。默认情况下您期望这种行为。

然而,这一点以及垃圾收集器的缺失也引入了引用循环的全局问题,没有经验的用户很容易遇到这个问题。当然,有很多方法可以控制它;您甚至可以编写有关正确处理引用循环的测试。我将在下一篇文章中展示更详细的防止内存泄漏的方法,订阅不要错过。

Combine 中没有与 DisposeBag 类似的东西。有一个 Cancellable(把我带回 Disposable),你可以取消并释放所有资源。然而,在 ARC 中使用 Cancellable 可能会非常令人困惑。这是一篇很棒的文章,它通过示例展示了 Combine 的问题。

我是 DisposeBag 的忠实粉丝。非常方便,而且非常简单。例如,有一种众所周知的清除单元格中订阅的模式:

swift 复制代码
final class Cell: UITableViewCell {
    private var disposeBag = DisposeBag()
    func prepareForReuse() {
        super.prepareForReuse()
        disposeBag = DisposeBag()
    }
    ...
}

我在当前项目中最大的单元中有七个订阅。也许我真的不想为七个 Cancellable 中的每一个编写这个清理代码。在我看来,添加一个类似类型的 CancelBag 是合乎逻辑的,但苹果工程师比我更了解他们的东西。因此,只能等待,祈祷。在极端情况下,您可以轻松提供自定义实现。

API

RxSwift vs Combine 不等于 Kotlin coroutines vs RxJava 问题。可以用来处理类似问题的工具和类似的工具并不相同。 API 是完全平等的。是的,文字可能略有不同,但它们是相同的框架,只是以不同的方式编写。如果您对更多细节感兴趣,这里有来自 RxSwift 主要维护者之一、出色的 Shai Mishali 的 RxSwift 和 Combine API 的比较

是的,没有 flatMapLatest 或常见的特征,如 MaybeCompletableDriver。但这只是实施细节。对于苹果来说,它们...... 没有必要。在尝试 SwiftUI + Combine 时,我没有遇到任何因它们缺席而出现的问题。

RxSwift 不会仅仅复制所有的 Combine API。但我会默默地窃取有意义且适用的运算符。例如,这里有一个很酷的 assign 运算符,它已经添加到 RxSwift 中。不要犹豫,RxSwift 使用起来会像 Combine 一样舒适。如果您有兴趣在 RxSwift 中使用您最喜欢的组合运算符,请参与本期。只要投票,我就会为你实现一切。

性能

我想说,RxSwift 和 Combine 一样快。但我不能对你撒谎。这是一个小测试用例,仅应用无意义的运算符。我们通常就是这样编程的,对吗?

结果令人失望。是的,我们很少过滤数百万个元素流,但尽管如此:

遗憾的是我没有额外的 6000 美元购买新的 Mac Pro,所以只有 1000 万个元素。该比率呈线性增长。我不会附上不同数量元素的图表,但您可以复制粘贴此测试并自行运行。

RxSwift 在底层启动许多接收器已经不是什么秘密了。它就是这样设计的,我怀疑有人会轻易找到更好的解决方案。然而,Combine 的设计很长一段时间以来都强调性能。这不仅仅是言语。

嗯...... 很好。显然,来自苹果的开发者没有任何障碍,所有的资源都掌握在手中,可以比社区做得更好。老实说,我不认为它会更好。性能的大幅提升总是好的,但是...... 试着记住您最后一次使用 XCTestCase.measure 是什么时候?我强烈怀疑你的 tableView 滚动不够快只是因为 RxSwift。

Sugar(语法糖?)

你可以同意也可以不同意,但 RxSwift 和 Combine 实际上是相同的框架。Combine 完全在现代 Swift 中实现,因此您可以使用它的协议并提供 Publishers 的自定义实现。但您不会编写自己的 Map,是吗?因此,我对这一变化不发表任何评论。开放性、扩展性良好。但这种开放性却让开发者拄着拐杖写错了,不尊重契约。该框架应该提供开箱即用的所需一切,并且不允许用户更改规则或重新发明轮子。

行业价值

总会有怀疑者。怀疑论者试图让我们相信电脑不适合简单用户,而 iPhone 则不可能。怀疑论者表示,Swift 只是一个玩具,只是为了吸引新的开发者,苹果将继续用 ObjC 编写。总是有人持怀疑态度,他们说反应式编程是黑魔法,没有什么比古老的委托模式更好的了。

现在社区很兴奋,每个人都喜欢 SwiftUI。但只有少数人考虑了反应式,事实上,反应式是实现应用程序的新方式的核心特征。这取决于你,但我想说这...... 非常重要。

这是 RxSwift 的失败吗?不,这是苹果的胜利。很多人已经注意到,这是长期以来开发者最耀眼的 WWDC。 SwiftUI 绝对很酷。在最新款 iPhone 销量不理想后,苹果需要重新夺回市场地位。他们分析社区请求并尽一切努力哄骗开发人员。他们试图让世界上的每个开发人员都想为苹果编写应用程序。老实说,他们做到了。

就是这样。反应式编程。应该说,RxSwift 在 iOS 开发中并不是很流行。虽然 Android 应用程序没有 RxJava 就无法实现,但我们(iOS 用户)仍然怀疑是否应该尝试这个库。 "这是第三方" 和 "代码太复杂,太神奇了" 成为反对 RxSwift 的流行论点。现在苹果公司宣布了一个反应式框架,意思是 "是的,伙计们。这就是 iOS 开发的未来。现在正式了。处理它" 显然,现在更多的开发人员会将委托更改为 Rx。如果他们不是...... 他们应该是。

iOS 13.0+

较低的 iOS 版本不支持 Combine。你能用它做什么?

  • 如果你目前正在使用 RxSwift,那么一两年就不用担心了。我看不出将代码库迁移到 Combine 有任何意义。也许有一天你会觉得使用自定义 RxSwiftCommunity 库没有任何意义,因为所有这些库都可以在官方框架中开箱即用。然后...... 你可以尝试删除 RxSwift。
  • 如果您现在想尝试在项目中做出反应,那么最好等待。从 RxSwift 迁移到 Combine 将相当复杂。是的,您可能认为 API 非常相似,但相信我,您会遇到问题。因此,只需在宠物项目中查看它,无需将其添加到您的生产中。
  • 如果你现在没有做出反应...... 好吧,正如我已经说过的...... 你绝对应该做出反应。

RxSwift 是目前响应式编程的一个很好的替代方案。您不需要支持 iOS 13.0+ 即可进行响应式编程。我想你可能会看到苹果的新东西。我很惊讶人们会喜欢:"哇,一种设置表格视图的方法,太方便了,太现代了。" 苹果并没有像往常一样发明任何新东西,他们只是让旧的变得更好。对于较低的 iOS 版本,您现在可以用一行配置您的表(我已经使用它两年了):

RxDataSources

值得注意的是,反应式编程框架围绕其自身形成了大量方便的扩展。对我来说,反应性已经成为简洁的代名词。您可以在我的上一篇文章中了解 RxSwift 的便利性。

RxSwift 社区真的很棒。因为反应性不仅仅是处理异步事件的一种方法,而且是一种思考、设计应用程序的方法。声明性、单向性、无状态组件...... 您现在就可以使用所有这些功能。类似的东西你必须与 SwiftUI 一起使用。您已经了解 Flutter 中的所有 BLoC 内容。

何去何从

我真的很想说 RxSwift 将永远存在,有一天我会向我的儿子解释它。但是这是错误的。 RxSwift 几年后就会消亡。这不仅仅是炒作的话,而是事实。你可以在这里阅读更多。最特别有趣的是 Krunoslav Zaher 的评论,他让 iOS 开发者的生活变得更加幸福。

你可以随心所欲地解释它,但对我来说,这是一次悲伤的告别。这是一项很棒的工作,我希望我能早点出生,站在这个存储库的起源上。我为此付出的努力太少了,现在正努力追赶。我们努力为对 Combine 感兴趣的用户提供更愉快的 RxSwift 体验。新的类似 Combine 的操作符即将推出。

但这一切都只是对梦想的追求。 RxSwiftCommunity 可以向 UIKit 添加任何扩展。但不幸的是,我们永远无法直接为 Apple 框架做出贡献。Combine 看起来是一个耐用的功能。 Apple 在 RealityKit 中支持它,SwiftUI 在底层使用它。这是合乎逻辑的。 RxSwift 永远只能成为一个让开发变得更容易的第三方。

正确的问题不是 "我应该使用 Combine 吗?",而是 "我到底应该什么时候开始这样做?"。这取决于您的要求。例如,在当前项目中,我的团队仅支持 iOS 12,因此,我们可能很快就会迁移到 SwiftUI + Combine 架构。伙计们,这就是未来,唯一的问题是 "你们多久才能准备好放弃你们的遗产,进入一个勇敢的新世界?"。没有人强迫你,但这是必要的。只是为了防止你的开发人员陷入抑郁。

开源

"为什么他们不开源 Combine?" 成为一个非常受欢迎的问题,这对我来说很奇怪。只是因为所有其他 Apple 框架都不是开源的。他们可能使用普通用户不允许的功能。他们不想解决问题、审查贡献者的 PR。因为他们比其他人能更好地处理这个问题。就是这样,我不想有任何其他理由同意该政策。

Subjective

抱歉,Publisher 是一个非常糟糕的名字。我们有一本由四人组成的书,具有众所周知的可观察模式。我们有伟大的埃里克・迈耶,毕竟,你称其为 Publisher?当然,我会习惯的,但是...... 在俄语中,Publisher 翻译为 "他",Observable 翻译为 "它"。苹果,多样性怎么样?

此外,RxSwift 支持开箱即用的 dark 模式,这一点我不能说 Joint。你的选择。

我的计划

首先,我要为 RxSwift 的美好生活喝点啤酒。我将进行一些有关 RxSwift 与 Combine 的技术讲座。老实说,我只是想让人们明白他们手中握着的是什么。不仅仅是大声喊出 "华丽"、"惊人" 或 "令人兴奋" 等词语,而是真正理解为什么这是...... 令人兴奋。这不仅仅是一个功能,它是 iOS 开发的新时代。我押注于 Combine 和 SwiftUI,并建议你也这样做。

10 年后,我打算成为一个老人,告诉大家我们是如何使用 RxSwift 的。而且,该死的,太棒了。

相关推荐
大熊猫侯佩11 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(三)
数据库·swiftui·swift
大熊猫侯佩11 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(二)
数据库·swiftui·swift
大熊猫侯佩11 小时前
用异步序列优雅的监听 SwiftData 2.0 中历史追踪记录(History Trace)的变化
数据库·swiftui·swift
大熊猫侯佩11 小时前
由一个 SwiftData “诡异”运行时崩溃而引发的钩深索隐(一)
数据库·swiftui·swift
season_zhu1 天前
iOS开发:关于日志框架
ios·架构·swift
大熊猫侯佩1 天前
SwiftUI 中如何花样玩转 SF Symbols 符号动画和过渡特效
swiftui·swift·apple
大熊猫侯佩1 天前
SwiftData 共享数据库在 App 中的改变无法被 Widgets 感知的原因和解决
swiftui·swift·apple
大熊猫侯佩1 天前
使用令牌(Token)进一步优化 SwiftData 2.0 中历史记录追踪(History Trace)的使用
数据库·swift·apple
大熊猫侯佩1 天前
SwiftUI 在 iOS 18 中的 ForEach 点击手势逻辑发生改变的解决
swiftui·swift·apple