防止表视图被重用(MVVM)
Prevent tableview from being reused (MVVM )
我知道如何在来回滚动后保留我们在 UITableView
上完成的操作。
现在我正在 MVVM 上做一个简单的 UITableView
它有一个 Follow 按钮 . 像这样。
单击后关注按钮更改为取消关注并在滚动后重置。
在哪里以及如何添加代码来防止这种情况?
这是表格视图代码
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
类型的自定义委托
我猜你的主要问题是 Button
标题在 滚动 上发生了变化,所以我发布了一个解决方案。
注意-:下面的代码没有遵循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 可以 delegate 到其他存储库来处理或自行处理。收到响应后 viewModel 更新其状态并与 View
(在我们的例子中 tableView
)通信到 re-render 本身。
我正在更新模型 object 的 extension
中的代码不应该在控制器 (model[indexPath!.row].buttonTitle = "Unfollow")
中,必须由 完成viewModel,一旦 viewModel 状态改变,它应该与视图通信到 re-render.
Cell
class 中的交互响应程序(按钮操作)应将操作委托给 viewModel 而不是 controller
.
Model
class 应该在它自己的单独文件中。
简而言之,viewModel 处理您的 View
的 State
,它应该是观看您的 model
更新的那个,然后改变它应该问 View 到 re-render.
您可以做更多的事情来遵循严格的 MVVM 方法并使您的代码更加松散耦合和可测试。以上几点可能不是 100% 正确我只是分享了我的一些基本想法。您可以在线查看文章以进行进一步跟进。
以上答案有效。但是我已经通过@Joakim Danielson 的建议来了解更新 View
时到底发生了什么,以及为什么它没有在 ViewModel
上更新
所以我更新了委托函数
ViewController
委托函数
func PersonFollowingTableViewCell1( _ cell: PersonFollowingTableViewCell, array : Person, tag : Int)
在这里,我调用了Viewmodel
中的数组,并在func
参数中将array
的值赋给它。
喜欢ViewModel().Vmarray[tag].currentFollow = array[tag].currentFollow
我知道如何在来回滚动后保留我们在 UITableView
上完成的操作。
现在我正在 MVVM 上做一个简单的 UITableView
它有一个 Follow 按钮 .
这是表格视图代码
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
类型的自定义委托
我猜你的主要问题是 Button
标题在 滚动 上发生了变化,所以我发布了一个解决方案。
注意-:下面的代码没有遵循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 可以 delegate 到其他存储库来处理或自行处理。收到响应后 viewModel 更新其状态并与View
(在我们的例子中tableView
)通信到 re-render 本身。我正在更新模型 object 的
extension
中的代码不应该在控制器(model[indexPath!.row].buttonTitle = "Unfollow")
中,必须由 完成viewModel,一旦 viewModel 状态改变,它应该与视图通信到 re-render.Cell
class 中的交互响应程序(按钮操作)应将操作委托给 viewModel 而不是controller
.Model
class 应该在它自己的单独文件中。
简而言之,viewModel 处理您的 View
的 State
,它应该是观看您的 model
更新的那个,然后改变它应该问 View 到 re-render.
您可以做更多的事情来遵循严格的 MVVM 方法并使您的代码更加松散耦合和可测试。以上几点可能不是 100% 正确我只是分享了我的一些基本想法。您可以在线查看文章以进行进一步跟进。
以上答案有效。但是我已经通过@Joakim Danielson 的建议来了解更新 View
时到底发生了什么,以及为什么它没有在 ViewModel
所以我更新了委托函数
ViewController
委托函数func PersonFollowingTableViewCell1( _ cell: PersonFollowingTableViewCell, array : Person, tag : Int)
在这里,我调用了Viewmodel
中的数组,并在func
参数中将array
的值赋给它。
喜欢ViewModel().Vmarray[tag].currentFollow = array[tag].currentFollow