我有以下代码在表格视图中显示数据。
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? ArticleTalbeViewCell else {
fatalError("ArticleTableViewCell not found")
}
let articleVM = self.articleListVM.articleAtIndex(indexPath.row)
// cell.viewModel = articleVM
cell.titlelabel?.text = articleVM.title
cell.descriptionLabel?.text = articleVM.description
return cell
}
}
现在,我的
代码cell.titlelabel?.text = articleVM.title
cell.descriptionLabel?.text = articleVM.description
做得好。
cell.viewModel = articleVM
是好的做法吗?
想象一下我必须将日期多次设置到单元格吗?这种方法cell.viewModel = articleVM
将节省几行。
UITableViewCell
的代码如下:
class ArticleTalbeViewCell: UITableViewCell {
var titlelabel:UILabel?
var descriptionLabel:UILabel?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.setupUI()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
fatalError("init(coder:) has not been implemented")
}
private func setupUI() -> () {
let label1 = UILabel()
label1.numberOfLines = 0
let label2 = UILabel()
label2.numberOfLines = 0
label2.textColor = UIColor.lightGray
label2.setContentHuggingPriority(UILayoutPriority.defaultHigh, for: NSLayoutConstraint.Axis.vertical)
titlelabel = label1
descriptionLabel = label2
let staview = UIStackView()
staview.axis = .vertical
staview.addArrangedSubview(label1)
staview.addArrangedSubview(label2)
staview.spacing = 8
staview.translatesAutoresizingMaskIntoConstraints = false // !important
self.contentView.addSubview(staview)
staview.topAnchor.constraint(equalTo: self.contentView.topAnchor,constant: 5).isActive = true
staview.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -5).isActive = true
staview.leftAnchor.constraint(equalTo: self.contentView.leftAnchor, constant: 5).isActive = true
staview.rightAnchor.constraint(equalTo: self.contentView.rightAnchor, constant: -5).isActive = true
}
}
ArticleListViewModel
代码如下:
struct ArticleListViewModel {
let articles:[Article]
}
extension ArticleListViewModel {
var numbeOfSections: Int {
return 1
}
func numOfRowsInSection(_ section: Int) -> Int {
return self.articles.count
}
func articleAtIndex(_ index: Int) -> ArticleViewModel {
let article = self.articles[index]
return ArticleViewModel(article)
}
}
struct ArticleViewModel {
private let article: Article
}
extension ArticleViewModel {
init(_ article: Article) {
self.article = article
}
}
extension ArticleViewModel {
var title: String {
return self.article.title ?? "null"
}
var description: String {
return self.article.description ?? "null"
}
}
ArticleList
代码如下:
import Foundation
struct ArticleList: Decodable {
let articles: [Article]
}
struct Article: Decodable {
let title: String?
let description: String?
let chines: String?
}
如何编辑“单元格”代码以实施cell.viewModel = articleVM
?
答案 0 :(得分:1)
首先,我认为给予cell.viewModel = articleVM
不会带来太多改变。由于您已经创建了 ArticleListViewModel 和 ArticleViewModel ,因此,如果您为表视图单元格创建了这些虚拟机,则将是相同的。但是,我可以为您提供一些在使用MVVM方法时所使用的建议。
您可以在表格视图单元格内添加新属性,然后使用属性观察器为其赋予一个值。
cell.article = articleVM
因此,您的cellForRowAt
方法不会太长,几乎就像将视图模型提供给单元格一样。
private var titlelabel:UILabel?
private var descriptionLabel:UILabel?
var article: ArticleViewModel? {
didSet {
guard let article = article else { return }
titlelabel?.text = article.title
descriptionLabel?.text = article.description
}
}
据我了解,您的第二个问题是您是否具有日期变量,并且cellForRowAt
方法内部的格式占用太多空间并且看上去很丑陋。这就是为什么需要在视图模型中进行业务逻辑的原因。您的表格视图单元格仅负责显示它而不设置其格式。希望对您来说很清楚。如果您有任何疑问可以询问。
答案 1 :(得分:0)
您必须使用cell
模型(即
cell
,而不是在ArticleTalbeViewCell
方法中配置dataSource
>
class ArticleTalbeViewCell: UITableViewCell {
private var titlelabel: UILabel?
private var descriptionLabel: UILabel?
//rest of the code...
func configure(with article: Article) {
self.titlelabel?.text = article.title
self.descriptionLabel?.text = article.description
}
}
在上面的代码中,
1。。无需将titlelabel
和descriptionLabel
暴露在class ArticleTalbeViewCell
之外。因此,将它们都标记为private
。
2。。您只需要与configure(with:)
实例一起调用Article
方法。
为什么使用方法而不是Article类型的属性?
在ArticleTalbeViewCell
配置一次之后,除非且除非在其他地方需要,否则无需将模型对象保存在cell
内。
在tableView(_:cellForRowAt:)
方法中,您只需在特定的configure(with:)
上与cell
实例一起在article
上调用indexPath
方法。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? ArticleTalbeViewCell else {
fatalError("ArticleTableViewCell not found")
}
let article = self.articleListVM.articleAtIndex(indexPath.row)
cell.configure(with: article)
return cell
}
此外,我认为不需要创建单独的ArticleViewModel
。它没有做任何特别的事情。它只是Article
上的一个额外包装。
您可以简单地从Article
中的articleAtIndex(_:)
方法返回extension ArticleListViewModel
类型,即
func articleAtIndex(_ index: Int) -> Article {
let article = self.articles[index]
return article
}
为什么要在自定义UITableViewCell
中进行配置?
这是因为您的tableView
可能包含多个自定义UITableViewCells
。在cell
中添加所有tableView(_:cellForRowAt:)
的配置将使代码繁重且无法读取。最好由cell
本身而不是cell
处理ViewController
的特定配置。