初始加载后从数据模型更新 uiTableViewCell

Updating uiTableViewCell from data model after intial load

我是 iOS 开发的新手,所以这个问题可能看起来微不足道。我搜索了一下,找不到关于这个问题的任何问题。但我想知道在从数据模型 初始加载单元格后 运行 时间 更改数据模型时更新 UITableView 的自定义单元格的正确方法是什么。从更改,我的意思是数据条目更改,而不是添加或删除数据。

这是一个例子。假设我有这些 DataModelDataModelCell 如下:

class DataModelView : UITableViewCell {
    @IBOutlet weak var mainLabel: UILabel!
}

class DataModel {
    var title: String = "" {
        didSet {
            // which cell this entry is connected to?
        }
    }
}

...
items: [DataModel] = []

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "DataModelView", for: indexPath)

    cell.mainLabel?.text = items[indexPath.item].title
    // addition line for each approach
    // approach 1:
    // items[indexPath.item].view = cell
    // approach 2:
    // items[indexPath.item].viewIndexPath = indexPath

    return cell
}

我的问题是,当我在 运行 时间更改数据模型 中的一个单元格 title 时,我想更新相应的单元格UI。我想知道在 UITableView.

中建立数据模型条目和单元格之间关系的最佳方法是什么

我想到了 3 种不同的方法。我想知道他们是否正确,或者有没有更好的方法:

第一种方法: weak 指向我的数据条目中单元格的指针,如下所示:

class DataModel {
    weak var view: DataModelView?
    var title: String = "" {
        didSet {
            view?.mainLabel?.text = title
        }
    }
}

第二种方法: 在我的数据条目中保留 IndexPath 个单元格,如下所示:

class DataModel {
    var viewIndexPath: IndexPath?
    var title: String = "" {
        didSet {
            // call delegate to controller and ask to update cell for viewIndexPath
        }
    }
}

第三种方法:不要保留与数据输入中的单元格对应的任何内容:

class DataModel {
    var title: String = "" {
        didSet {
            // call delegate to controller and ask to find and update cell for self
        }
    }
}

在前两种方法中,我在数据模型中保持单元格和数据模型之间的关系。在第三种方法中,我需要在控制器中保持这种关系。

这些方法都正确吗(尤其是第一种)?你推荐哪一个?通常最好的方法是什么?

我看到人们在他们的视图中保留指向数据模型的指针,以便从视图中更新数据模型。我想知道它在其他方面是否也正确(第一种方法)。

应该是这样的

class DataModelView: UITableViewCell {
    @IBOutlet weak var mainLabel: UILabel!
    var yourModel: DataModel? {
       didSet {
         mainLabel.text = yourModel?.title
       }
}

在你的 cellForRowAt

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DataModelView", for: indexPath)

cell.yourData = items[indexPath.item]
return cell
}

在您的项目数组中更改任何项目后,只需调用

tableView.reloadData()

第4种方法:单元格中数据模型的弱指针和键值观察

class DataModelView : UITableViewCell {
   @IBOutlet weak var mainLabel: UILabel!

   var observation : NSKeyValueObservation?

   weak var model : DataModel? {
       didSet {
           if model == nil { observation = nil }
           else {
               observation = model!.observe(\.title, options: [.new])  { [weak self] (model, _) in
                  self?.mainLabel.text = model.title
               }
           }
       }
    }
}

KVO 需要从 NSObject

继承
class DataModel : NSObject {
    @objc dynamic var title: String = ""
}

cellForRow传递模型

let cell = tableView.dequeueReusableCell(withIdentifier: "DataModelView", for: indexPath) as! DataModelView
cell.model = items[indexPath.row]

并移除 didEndDisplaying

中的观察者
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    (cell as! DataModelView).observation = nil
}