我坚持一个设计决策,为表视图的单元格创建视图模型。每个单元格的数据由数据源类提供(具有Contacts
数组)。在MVVM
中,只有视图模型可以与模型对话,但将数据源放在视图模型中是没有意义的,因为它可以访问所有单元格的数据,将数据源放入其中也是错误的。查看控制器,因为它不能引用数据。还有其他一些关键时刻:
cellForRowAtindexPath
不得放在视图模型中,因为
它不应包含任何UI引用在MVVM
关系中为单元格“插入”数据源的正确方法是什么?感谢。
答案 0 :(得分:84)
让我从一些理论开始。 MVVM是Microsoft的Silverlight和WPF的Presentation Model(或应用程序模型)的专业化。 这种UI架构模式背后的主要思想是:
好处如你所说:
回到你的问题,UITableViewDataSource
协议的实现属于体系结构的视图部分,因为它依赖于UI框架。请注意,为了在代码中使用该协议,该文件必须导入UIKit。此外,返回视图的tableView(:cellForRowAt:)
等方法在很大程度上依赖于UIKit。
然后,您的数组Contacts
,确实是您的模型,无法通过视图(数据源或其他方式)进行操作或查询。相反,您将视图模型传递给表视图控制器,在最简单的情况下,它具有两个属性(我建议它们存储,而不是计算属性)。其中一个是节数,另一个是每个节的行数:
var numberOfSections: Int = 0
var rowsPerSection: [Int] = []

视图模型使用对模型的引用进行初始化,作为初始化的最后一步,它设置了这两个属性的值。
视图控制器中的数据源使用视图模型的数据:
override func numberOfSections(in tableView: UITableView) -> Int {
return viewModel.numberOfSections
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return viewModel.rowsPerSection[section]
}

最后,您可以为每个单元格设置不同的视图模型结构:
struct ContactCellViewModel {
let name: String
init(contact: Contact) {
name = contact.name ?? ""
}
}

UITableViewCell
子类将知道如何使用该结构:
class ContactTableViewCell: UITableViewCell {
var viewModel: ContactCellViewModel!
func configure() {
textLabel!.text = viewModel.name
}
}

为了获得每个单元格的相应视图模型,表视图视图模型将提供一个生成它们的方法,并且可以用于填充视图模型的数组:
func viewModelForCell(at index: Int) -> ContactCellViewModel {
return ContactCellViewModel(contact: contacts[index])
}

正如您所看到的,这里的视图模型是唯一与模型(您的Contacts
数组)对话的模型,而视图只与视图模型对话。
希望这有帮助。
答案 1 :(得分:-4)
除非您遇到使用Model-View-ViewModel
解决的特定问题,否则尝试仅针对“最佳做法”采用该问题最终会导致许多不必要的复杂性。
您的数据源负责填充表格。除了您的数据源之外,其他任何内容都不需要引用contacts
,因为它会使用此数据更新您的表格。
View Models
只有在您需要进行复杂的UI交互和更新时才会发挥作用。 VM负责封装您的视图状态,例如......
对视图进行更改后,View Model
有责任对Model
(必要时)进行更新,以反映对Model
所做的更改通过用户界面。
综上所述,View Models在IOS 中没有意义,因为IOS在名为View Controllers
的设计方法中使用MVC
(模型 - 视图 - 控制器)