防止表视图被重用(MVVM)
Posted
技术标签:
【中文标题】防止表视图被重用(MVVM)【英文标题】:Prevent tableview from being reused (MVVM ) 【发布时间】:2021-06-13 08:26:07 【问题描述】:在来回滚动之后,我知道如何保存我们对 UITableView
所做的操作。
现在我在 MVVM 上做一个简单的UITableView
其中有一个关注按钮 . 像这样。
点击后跟随按钮变为取消关注,滚动后重置。
在哪里以及如何添加代码来防止这种情况发生?
这是表格视图代码
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return Vm.personFollowingTableViewViewModel.count
var selectedIndexArray:[Int] = []
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
guard let cell = tableView.dequeueReusableCell(withIdentifier: FollowList_MVVM.PersonFollowingTableViewCell.identifier , for: indexPath) as? PersonFollowingTableViewCell else
return UITableViewCell()
cell.configure(with: Vm.personFollowingTableViewViewModel[indexPath.row])
cell.delegate = self
return cell
和configure(with: )
函数
@objc public func didTapButton()
let defaultPerson = Person(name: "default", username: "default", currentFollowing: true, image: nil)
let currentFollowing = !(person?.currentFollowing ?? false)
person?.currentFollowing = currentFollowing
delegate?.PersonFollowingTableViewCell(self, didTapWith: person ?? defaultPerson )
configure(with: person ?? defaultPerson)
func configure(with person1 : Person)
self.person = person1
nameLabel.text = person1.name
usernameLabel.text = person1.username
userImageview.image = person1.image
if person1.currentFollowing
//Code to change button UI
使用Person
类型的自定义委托
【问题讨论】:
如果您真的在使用 MVVM,那么您的视图模型应该包含您的模型对象(Person)而不是您的单元格 @JoakimDanielson 你能详细说明一下吗?在 ViewModel 中,我只有一些基于模型的硬编码数据 当你更新了一个人时,你至少需要告诉视图模型,保存数据的是视图模型,而不是单元格。单元格中的 Person 对象应仅被视为原始数据的副本,如前所述,原始数据位于视图模型中。 @JoakimDanielson 谢谢。我对此做了更多参考,并用我自己的答案进行了更新 【参考方案1】:我猜你的主要问题是 Button
标题在 scroll 上被更改,所以我发布了一个解决方案。
注意-:下面的代码不遵循MVVM。
控制器-:
import UIKit
class TestController: UIViewController
@IBOutlet weak var testTableView: UITableView!
var model:[Model] = []
override func viewDidLoad()
for i in 0..<70
let modelObject = Model(name: "A\(i)", "Follow")
model.append(modelObject)
extension TestController:UITableViewDelegate,UITableViewDataSource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
return model.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TestTableCell
cell.dataModel = model[indexPath.row]
cell.delegate = self
return cell
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
return 100
extension TestController:Actions
func followButton(cell: UITableViewCell)
let indexPath = testTableView.indexPath(for: cell)
model[indexPath!.row].buttonTitle = "Unfollow"
testTableView.reloadRows(at: [indexPath!], with: .automatic)
class Model
var name: String?
var buttonTitle: String
init(name: String?,_ buttonTitle:String)
self.name = name
self.buttonTitle = buttonTitle
单元格-:
import UIKit
protocol Actions:AnyObject
func followButton(cell:UITableViewCell)
class TestTableCell: UITableViewCell
@IBOutlet weak var followButtonLabel: UIButton!
@IBOutlet weak var eventLabel: UILabel!
var dataModel:Model?
didSet
guard let model = dataModel else
return
followButtonLabel.setTitle(model.buttonTitle, for: .normal)
eventLabel.text = model.name
weak var delegate:Actions?
override func awakeFromNib()
super.awakeFromNib()
// Initialization code
override func setSelected(_ selected: Bool, animated: Bool)
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
@IBAction func followAction(_ sender: Any)
delegate?.followButton(cell:self)
要将其转换为 MVVM 方法,您需要更改和移出的东西很少。
viewDidLoad
中的循环不应该存在。这将是一些 API 调用,应该由 viewModel 处理,viewModel 可以将其委托 到其他存储库来处理或自行处理。收到响应后 viewModel 更新其状态并与View
(在我们的例子中为tableView
)通信以重新渲染自身。
我更新模型对象的extension
中的代码不应该在控制器(model[indexPath!.row].buttonTitle = "Unfollow")
中,这必须由viewModel 完成,并且一旦viewModel它应该与视图通信以重新渲染的状态更改。
Cell
类中的交互响应器(按钮操作)应将操作委托给 viewModel 而不是 controller
。
Model
类应该在它自己的单独文件中。
简而言之,viewModel 处理您的View
的State
,它应该是观看您的model
更新的人,并且在更改时它应该询问View 重新渲染。
您可以做更多的事情来遵循严格的MVVM 方法并使您的代码更加松散耦合和可测试。以上几点可能不是 100% 正确我刚刚分享了我的一些基本想法。您可以在线查看文章以进一步跟进。
【讨论】:
【参考方案2】:以上答案有效。但是我已经查看了@Joakim Danielson 的建议,以了解更新View
时究竟发生了什么以及为什么它没有在ViewModel
上更新
所以我对委托函数进行了更新
ViewController
委托函数
func PersonFollowingTableViewCell1( _ cell: PersonFollowingTableViewCell, array : Person, tag : Int)
在这里,我调用了Viewmodel
中的数组,并将func
参数中array
的值分配给它。
点赞ViewModel().Vmarray[tag].currentFollow = array[tag].currentFollow
【讨论】:
以上是关于防止表视图被重用(MVVM)的主要内容,如果未能解决你的问题,请参考以下文章
RxSwift MVVM 表视图/集合视图,用户输入单元表示状态