带有 RxSwft 的 iOS MVVM:无处不在的 viewmodel 的缺点是啥?
Posted
技术标签:
【中文标题】带有 RxSwft 的 iOS MVVM:无处不在的 viewmodel 的缺点是啥?【英文标题】:iOS MVVM with RxSwft: what is the drawback with viewmodel everywhere?带有 RxSwft 的 iOS MVVM:无处不在的 viewmodel 的缺点是什么? 【发布时间】:2021-12-27 17:05:04 【问题描述】:RxSwft 非常适合 ios MVVM。
将视图模型放在任何地方,违反得墨忒耳定律(最少知识原则)。
还有什么缺点?
会不会导致内存泄露?
这是一个例子:
ViewController 有一个 viewModel
ViewModel 有一些事件信号,比如下面的返回事件
class ViewModel
let backSubject = PublishSubject<String>()
ViewController 有contentView
和viewModel
,以及contentView
init 和viewModel
lazy var contentView: ContentView =
let view = ContentView(viewModel)
view.backgroundColor = .clear
return view
()
在viewController中订阅了ViewModel的各种主题,用于处理其他部分视图
viewController
是调度中心。
ViewModel
是事件传输站。 ViewModel
无处不在,在Controller中,在View中,收集不同的事件触发器。
代码很意大利面
在ContentView
中,用户点击rx事件,绑定到viewController中的viewModel
tapAction.bind(to: viewModel.backSubject).disposed(by: rx.disposeBag)
用户事件很容易连接起来。
但实际上存在内存泄漏。
那么其他的缺点是什么?
【问题讨论】:
【参考方案1】:ViewModel 没有违反 Demeter 法则,但确实违反了单一职责原则。您解决这个问题的方法是使用多个视图模型,每个功能一个,而不是整个屏幕的单个视图模型。这将使视图模型更具可重用性和可组合性。
如果您将视图模型设置为单个函数,将多个 Observable 作为输入并返回单个 Observable,您还将消除任何内存泄漏的可能性。
例如:
func textFieldsFilled(fields: [Observable<String?>]) -> Observable<Bool>
Observable.combineLatest(fields)
.map $0.allSatisfy !($0 ?? "").isEmpty
您可以根据是否已填写所有文本字段,将上述内容附加到要启用按钮的任何场景。
您满足 SRP,并且由于对象分配是自动处理的,因此无需担心上述操作会泄漏内存。
【讨论】:
【参考方案2】:你是对的,有一些缺点,如果你只想要一个数据绑定,我建议改用Combine
,因为不需要第三方库,你已经有了。当您将RxSwift
用作语言的一部分时,RxSwift
是一个非常强大的工具,而不仅仅是用于数据绑定。
根据我与RxSwift
合作的经验提出的一些建议:
-
尝试将 VM 设为结构,而不是类。
避免在 VM 中使用 DisposeBag,而是让 VC 订阅所有内容(更好地避免内存泄漏)。
为子视图、单元格、子 VC 和非共享虚拟机创建自己的 VM。
由于您的 VC 是一个调度中心,我将为您的内容视图制作一个单独的 VM,并通过您的控制器在 ContentView
VM
和 ViewController
VM
之间进行通信。
【讨论】:
仅供参考,就提问者的担忧而言,Combine 并不比 RxSwift 好...... @DanielT。我只是提到了与 RxSwift 相比,Combine 内置框架。我回答的重点不是简单地使用组合)以上是关于带有 RxSwft 的 iOS MVVM:无处不在的 viewmodel 的缺点是啥?的主要内容,如果未能解决你的问题,请参考以下文章
带有 ModalPresentationStyle 的弹出框不在 iOS 7 iPad 中居中