带有 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 有contentViewviewModel,以及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 VMViewController VM 之间进行通信。

【讨论】:

仅供参考,就提问者的担忧而言,Combine 并不比 RxSwift 好...... @DanielT。我只是提到了与 RxSwift 相比,Combine 内置框架。我回答的重点不是简单地使用组合)

以上是关于带有 RxSwft 的 iOS MVVM:无处不在的 viewmodel 的缺点是啥?的主要内容,如果未能解决你的问题,请参考以下文章

带有 ModalPresentationStyle 的弹出框不在 iOS 7 iPad 中居中

(ZK 7) 自动填充不绑定我的数据(MVVM 和作曲家)

带有 RxSwift 的 MVVM

使用 Swift 的带有 MVVM 的 UITableView

带有自定义过滤器的 Kendo MVVM Grid

使用带有棱镜的 MVVM 在视图之间切换