iOS MVVM 处理初始视图状态

Posted

技术标签:

【中文标题】iOS MVVM 处理初始视图状态【英文标题】:iOS MVVM handling initial view state 【发布时间】:2018-09-21 04:43:50 【问题描述】:

我正在尝试在 Objective C 中使用没有 Rx 的 MVVM,基本上类似于 MVP。我有一些非常基本的疑问想要解决

1.) 如何在视图中加载初始视图状态,基于配置。即当 UI 组件的初始状态可以根据某些配置值更改时。例如。视图中的按钮最初可以根据全局配置启用/禁用/隐藏。在一个视图中可能有很多 UI 组件的情况下,应该如何呈现这个初始视图状态?

视图模型是否应该将此配置(或视图状态对象)传递给视图并由视图决定如何呈现自己?或 视图模型是否应该将每个 UI 元素的状态传递给视图? 在 Rx 的情况下,VM 是否应该有一个视图状态属性或每个 UI 组件的状态属性?

2.) 如何处理各个 UI 组件的状态?

VM 是否应该通过 enableButton1、hideTextView 等方法要求视图更新其视图状态或 它应该只是将“事件”或数据传递给视图,并让视图决定如何对这些事件做出反应。 在 Rx 世界中,视图应该与单个状态属性绑定还是仅与事件属性绑定?

3.) 我很困惑谁应该触发某些操作,例如,让我们说“验证”。例如,在登录屏幕中,谁应该触发电子邮件/密码值的验证?

应查看要求 VM 验证,然后要求执行登录过程或 是否应该仅通过电子邮件/密码值将单击操作传递给 VM,然后由 VM 决定是否进行验证以及验证通过或失败时如何处理?

【问题讨论】:

【参考方案1】:

哇,这个问题包含了很多问题......让我们看看我能梳理出什么:

在一个视图中可能有很多 UI 组件的情况下,这个初始视图状态应该如何呈现?

当不使用响应式系统时,无论是在 Objective-C 还是 Swift 中,我的视图控制器最终都会得到一个在 viewDidLoad 中调用的 configureWithViewModel: (Obj-C) 或 configure(viewModel:) (swift) 函数。视图模型更改的时间。调用configure方法时,会在viewDidLoad中渲染初始状态。

视图模型是否应该将此配置(或视图状态对象)传递给视图并由视图决定如何呈现自己? View 模型是否应该将每个 UI 元素的状态传递给视图?

视图决定如何呈现自己,viewModel决定应该是什么值。 viewModel 只处理动态的视图部分。因此,例如,如果 UILabel 中唯一不同的是文本,那么 viewModel 会为文本提供一个字符串。如果 UILabel 也更改了 textColor,那么 viewModel 会同时提供 String 和 UIColor。

在 Rx 的情况下,VM 应该有一个视图状态属性还是每个 UI 组件的状态属性?

就个人而言,我为 viewModel 的每个动态视图提供了一个单独的 Observable,但在非 Rx 上下文中,我觉得这太复杂了,并且只有一个 update 可以同时提供所有状态。

如何处理各个 UI 组件的状态?

VM 是否应该通过 enableButton1、hideTextView 等方法要求视图更新其视图状态或 它应该只是将“事件”或数据传递给视图,并让视图决定如何对这些事件做出反应。

通过数据。观点并没有决定。例如 UIButton 有一个 isEnabled 属性。本例中的数据显然是Bool。 viewModel 提供了 Bool,而 ViewController 只是将该 bool 分配给 View(或者 View 将其分配给自己。)

在 Rx 世界中,视图应该与单个状态属性绑定还是仅与事件属性绑定?

状态属性。类似:

viewModel.isMyButtonEabled
    .bind(to: myButton.rx.isEnabled)

我很困惑谁应该触发某些操作,例如,让我们说“验证”。例如,在登录屏幕中,谁应该触发电子邮件/密码值的验证?

上面的措辞有点混乱。没有什么“触发操作”。当输入某些内容时,视图的输入部分会通知视图模型,并且视图模型要么忽略该输入,要么更新其状态。如果它更新其状态,那么它将更新发送到视图的输出部分。因此,以验证为例,您可以执行以下两项操作之一:

当用户点击“发送”按钮时,视图模型会收到电子邮件和密码。它负责做什么,并根据这些字符串的值更改其状态。然后它通知视图控制器它的状态已经改变。

当用户在每个文本字段中输入数据时,甚至可能是每个单独的字符,视图模型都会收到当前文本字段的值。它负责做什么,并根据这些字符串的值更改其状态。然后它通知视图控制器它的状态已经改变。

应查看要求 VM 验证,然后要求执行登录过程或 是否应该仅通过电子邮件/密码值将单击操作传递给 VM,然后由 VM 决定是否进行验证以及验证通过或失败时如何处理?

后者。我们的想法是将尽可能多的工作移出视图控制器,以便更容易控制/测试。

【讨论】:

感谢您回答这个巨大的问题。我几乎同意你的所有观点,我的思考过程也倾向于这一点。我有一个问题,但是当 VM 必须为 UI 表示状态提供数据时,例如 buttonText、buttonColor(状态的 3 种颜色)等。如果复杂的 UI 具有许多 UI 元素和状态,我们不会过多地污染 VM 吗?我们不是让 VM 在特定类型的视图下工作吗?如果 UI 发生变化,我们也必须更改 VM。虚拟机是否应该始终针对特定视图,我知道根据定义它是但是.. ViewModel 是将逻辑与效果分离;这不是关于隔离变化。编写良好的视图模型将允许您测试您的逻辑 在屏幕上显示任何内容、进行网络调用或保存/读取存储/从存储中读取。它会将您的视图控制器变成humble object

以上是关于iOS MVVM 处理初始视图状态的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI MVVM:父视图更新时重新初始化子视图模型

mvvm模式的简单介绍

ios MVVM实践 刷新网络请求+tableView展示数据

MVVM的本质:视图逻辑处理视图管理视数中间层

iOS:如何使用 MVVM 将模型从视图模型传递到视图模型?

使用 MVVM 帮助器的视图模型中的 Xamarin 事件处理程序