从 nib 初始化自定义 UITableViewCell,无需 dequeueReusableCellWithIdentifier

Nik*_*Kov 2 ios swift

迅速

我需要制作一个单元格数组。我有一些带有 nib 文件的自定义单元格类(继承自 UITableViewCell)。

如何在不在表视图中注册笔尖并执行 dequeueReusableCellWithIdentifier 的情况下初始化单元格?我这样做了,但不认为它会起作用:

var labelCell = CustomCellClass.initialize()
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 5

我从其他地方的评论中的讨论推断,您不允许单元格出队和重用的原因是您在跟踪单元格中捕获的用户输入时遇到困难。

\n\n

最重要的是,您确实应该允许单元出队并重新使用,并适当地处理它。如果您在重复使用单元格时遇到问题,可以通过将 \xe2\x80\x9cmodel\xe2\x80\x9d (即您的数据)与 \xe2\x80\x9cview\xe2\x80\x9d 分开来解决(即 UIKit 控件)。这是模型-视图-控制器模式的精神,但在任何具有关注点分离的模式(例如,MVVP、MVP 等)中都是如此。

\n\n

关键是,当单元格中的值发生变化时,单元格应该立即告诉视图控制器,以便视图控制器可以立即更新模型。然后,当视图控制器稍后需要对与特定行关联的值执行某些操作时,它不会从单元格中检索它,而是从它自己的模型中检索它。

\n\n

因此,我可以为单元格定义一个协议,以通知表视图其文本字段已更改:

\n\n
protocol CustomCellDelegate: class {\n    func cell(_ cell: CustomCell, didUpdateTextField textField: UITextField)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我定义一个调用该委托的单元类:

\n\n
class CustomCell: UITableViewCell {\n    weak var delegate: CustomCellDelegate?\n\n    @IBOutlet weak var customTextField: UITextField!          // hook up outlet to this property in IB\n\n    @IBAction func didChangeValue(_ sender: UITextField) {      // hook up "editing changed" action for the text field to this method in IB\n        delegate?.cell(self, didUpdateTextField: sender)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,视图控制器将:

\n\n
    \n
  • 向相关 NIB 注册重用标识符;
  • \n
  • 在 中cellForRowAt,填充文本字段并将其自身指定为该单元格的委托;和
  • \n
  • 如果用户更改任何内容,则处理didUpdateTextField更新模型的方法。
  • \n
\n\n

因此,类似:

\n\n
class ViewController: UITableViewController {\n\n    var values = ["One", "Two", "Three"]  // some initial values\n\n    private let cellIdentifier = "CustomCell"\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n\n        // if you\xe2\x80\x99re using NIBs, you register them. \n        // obviously if using prototype cells in your storyboard, this isn\xe2\x80\x99t necessary.\n\n        tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: cellIdentifier) // or use cell prototype with storyboard identifer specified\n    }\n}\n\n// MARK: - UITableViewDataSource\n\nextension ViewController {\n\n    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {\n        return values.count\n    }\n\n    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {\n        let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! CustomCell\n\n        // populate cell and specify delegate\n\n        cell.delegate = self\n        cell.customTextField.text = values[indexPath.row]\n\n        return cell\n    }\n}\n\n// MARK: - CustomCellDelegate\n\nextension ViewController: CustomCellDelegate {\n    func cell(_ cell: CustomCell, didUpdateTextField textField: UITextField) {\n        // when the cell tells us that its text field\'s value changed, update our own model\n\n        if let indexPath = tableView.indexPath(for: cell), let string = textField.text {\n            values[indexPath.row] = string\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

许多人可能倾向于通过将IBAction文本字段直接挂接到视图控制器方法来进一步简化这一点。这是可行的,并且消除了对此协议的需要,但问题是您需要弄清楚这个特定的 UIKit 控件与哪一行相关联。常见的技巧是在视图层次结构中向上导航以识别适当的单元格(例如,文本字段通常位于单元格内的内容视图中,因此您可以抓取textField.superview.superview as! UITableViewCell),但这对我来说有点脆弱。

\n\n

但不管这个小细节如何,希望这能说明更广泛的模式。您不应该尝试让单元格跟踪用户输入,而应该让单元格(\xe2\x80\x9cview\xe2\x80\x9d)立即更新任何数据更改的控制器,然后视图控制器立即更新模型,您不再需要担心 iOS 采用的单元重用优化。

\n\n

对于 Swift 2 演绎版,请参阅此答案的先前修订版

\n