ios - 防止 RxSwift 中的冗余操作
问题描述
我正在用 RxSwift 开始我的冒险,在 js 中使用 React 已经有了一些经验。我认为我的问题很常见,但我不确定如何以简洁抽象的方式描述它,所以我将在示例中描述它。
我正在构建显示一些图表的 iOS 应用程序。感兴趣的部分包括 ChartAreaController、ChartInfoController,它们都嵌入在 ChartController 中。第一个控制器是显示一些图形的区域(基于 rx chartData 属性),第二个控制器将有一个滑块供用户限制显示 x 值(rx selectedXRange 属性),该值被限制在某个最小值和最大值之间。最小值/最大值由当前图表数据定义。
在 ChartController 中定义滑块更改更新图表时的行为:
override func viewDidLoad() {
super.viewDidLoad()
(...)
chartInfoController.selectedXRange.asObservable()
.subscribe(onNext: { [unowned self] selectedXRange in
(...)
let chartData = self.filterChartData(from: self.rawChartData, in: selectedXRange)
self.chartAreaController.chartData.accept(chartData)
}).disposed(by: disposeBag)
filterChartData() 方法只是过滤掉不在范围内的数据,但为了论证的目的,我们可以假设它非常昂贵,我不希望它在不需要时运行两次。
当用户更改他或她想要显示的图表时,新数据从服务器到达(同样是 ChartController):
private func handleNewData(_ rawChartData: ChartData) {
self.rawChartData = rawChartData
guard let allowedXRange = rawChartData.xRange() else { return }
let selectedXRange = chartInfoController.selectedXRange.value
let newSelectedXRange = calculateSelectedXRange(currentSelectedDays: selectedDaysRange, availableDaysRange: daysRange)
let chartData = filterChartData(from: rawChartData, in: selectedXRange)
self.chartInfoController.allowedXRange = allowedXRange //this line is not crucial
self.chartInfoController.selectedXRange.accept(newSelectedXRange)
self.chartAreaController.chartData.accept(rawChartData)
}
因此,在新图表数据到达时,由于数据的新最小值/最大值,可能必须修剪当前选择的 xRange。因此,该方法的副作用将是更改 selectedXRange 并运行我之前粘贴的订阅。因此,当新数据到达时,chartData 会更新两次,我不希望它发生。
当然我可以注释掉handleNewData()方法的最后一行,但我不是很喜欢它,因为handleNewData()存在的主要原因是设置chartData,并且注释掉的行的目标是由于该方法的副作用(即更新滑块)而实现。不能接受的。
无论如何,我对 chartData 添加了油门,因为快速移动的滑块会导致许多更新,这部分解决了我的问题(chartData 只更新了一次)。但是您可能还记得 filterChartData() 方法的成本很高,而且这部分仍然会运行两次。
所以一个问题是,如果我解决问题的总体布局是可以的,还是应该以不同的方式处理?在这一点上,我得出的结论是,我正在寻找某种方法来临时禁用 selectedXRange 上的特定订阅(而不破坏对该变量的其他订阅)。暂时的意思:
(...)
//disable subscription
self.chartInfoController.selectedXRange.accept(newSelectedXRange)
self.chartAreaController.chartData.accept(rawChartData)
//enable subscription
(...)
这对我来说似乎是合法的,因为 ChartController 作为订阅的所有者和值的更改者可能希望在适合他的时候禁用订阅(它?)。
RxSwift 是否支持这样的东西?如果没有,那么我想我可以自己实现它,例如通过 ChartController 中的 bool 属性,或者通过将订阅添加到单独的 disposeBag,我将处理然后重新创建订阅。但如果这样做是好事呢?例如,当出现一些错误时,bool 解决方案可能容易处理不当,并且 dispose/recreate 可能会以某种方式代价高昂,并且可能不打算像这样使用 dispose。
有没有更好的做法来处理这种情况?正如我所说,我认为这个问题很常见,所以我希望有一个规范的解决方案:) 感谢您的任何回答,对于冗长的帖子感到抱歉。
解决方案
所以一个问题是,如果我解决问题的总体布局是可以的,还是应该以不同的方式处理?
正确编写的 UI 输入元素 observable 只会在用户对 UI 进行更改时触发,而不是在程序进行更改时触发。例如:
textField.rx.text.orEmpty.subscribe(onNext: { print($0) })
只会在用户输入 textField 时打印一个值,而不是在您调用textField.text = "foo"
或从绑定时打印.bind(to: textfield.rx.text)
。
如果您编写了 ChartInfoController,我建议您修改它以使其与其他 UI 元素一样工作。如果您没有编写它,请将问题提交给开发人员/维护人员。
RxSwift 是否支持 [暂时禁用特定订阅] 之类的功能?
这取决于您所说的“暂时禁用”是什么意思。它不支持静默取消订阅和重新订阅,但是有很多运算符会过滤掉他们收到的一些事件,同时传递其他事件。例如filter
, throttle
, debounce
, ignoreElements
... 有很多人这样做。
有没有更好的做法来处理这种情况?
然后上面提到了最佳解决方案。
推荐阅读
- plot - 如何仅在 x 个条形定义的范围内绘图?
- python - BeautifulSoup:为什么 .select 方法返回一个空列表?
- java - 服务器错误,状态代码:400,错误代码:100005,消息:您已超出组织的内存限制
- css - CSS 的样式链接语法
- vue.js - 我可以在 Vue 上拥有一个全局 mixin 和一个导入的 mixin 吗?
- java - 在 gitlab 中安排一个仅执行单个测试的管道
- javascript - 如何在对象数组中找到所有具有 ID 的记录?
- python - Python套接字setdefaulttimeout方法不起作用
- wordpress - 如何在 WordPress 中将重力形式添加到博客页面(帖子页面)
- git - 在 Visual Studio Code 中尝试“git revert”时出错