防止 tableview 被重用 (MVVM)

问题描述

我知道如何在来回滚动后保留我们在 UITableView 上所做的操作。

现在我正在 MVVM 上做一个简单的 UITableView 它有一个“关注”按钮 .

follow button

像这样。 点击后关注按钮变为取消关注,滚动后重置。 在哪里以及如何添加代码来防止这种情况发生?

这是tableview代码

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 类型的自定义委托

解决方法

我猜您的主要问题是在 scroll 上更改了 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 方法,您需要更改和移出的东西很少。

  1. 我在 viewDidLoad 中的循环不应该在那里。这将是一些 API 调用,应该由 viewModel 处理,并且 viewModel 可以委托到其他存储库来处理或自行处理。收到响应后,viewModel 更新其状态并与 View(在我们的示例中为 tableView)通信以重新呈现自身。

  2. 我正在更新模型对象的 extension 中的代码不应在控制器 (model[indexPath!.row].buttonTitle = "Unfollow") 中,这必须由 viewModel 完成,并且一旦 viewModel 状态更改,它应该与视图通信以重新渲染。

  3. Cell 类中的交互响应者(按钮操作)应将操作委托给 viewModel 而不是 controller

  4. Model 类应该在它自己的单独文件中。

简而言之,viewModel 处理您的 StateView,它应该是监视您的 model 以获取更新的那个,并且在更改时它应该询问 查看重新渲染。

为了遵循严格的 MVVM 方法,您可以做更多的事情,并使您的代码更加松散耦合和可测试。以上几点可能不是 100% 正确我刚刚分享了我的一些基本想法。您可以在线查看文章以进一步跟进。

,

上述答案有效。但是我已经阅读了@Joakim Danielson 的建议,以了解更新 View 时到底发生了什么以及为什么它没有在 ViewModel

上更新

所以我更新了委托函数

  1. ViewController 委托函数

    func PersonFollowingTableViewCell1( _ cell: PersonFollowingTableViewCell,array : Person,tag : Int)

在这里,我调用了 Viewmodel 中的数组,并将 array 参数中的 func 的值分配给它。

喜欢ViewModel().Vmarray[tag].currentFollow = array[tag].currentFollow

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...