我从其他地方的评论中的讨论推断,您不允许单元格出队和重用的原因是您在跟踪单元格中捕获的用户输入时遇到困难。
最重要的是,您确实应该允许单元出队并重新使用,并适当地处理它。如果您在重用单元格时遇到问题,可以通过将“模型”(即您的数据)与“视图”(即 UIKit 控件)分离来解决。这就是我们的精神模型-视图-控制器模式 https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html,但在任何具有关注点分离的模式(例如 MVVP、MVP 等)中都是如此。
关键是,当单元格中的值发生变化时,单元格应该立即告诉视图控制器,以便视图控制器可以立即更新模型。然后,当视图控制器稍后需要对与特定行关联的值执行某些操作时,它不会从单元格中检索它,而是从它自己的模型中检索它。
因此,我可以为单元格定义一个协议,以通知表视图其文本字段已更改:
protocol CustomCellDelegate: class {
func cell(_ cell: CustomCell, didUpdateTextField textField: UITextField)
}
然后我定义一个调用该委托的单元类:
class CustomCell: UITableViewCell {
weak var delegate: CustomCellDelegate?
@IBOutlet weak var customTextField: UITextField! // hook up outlet to this property in IB
@IBAction func didChangeValue(_ sender: UITextField) { // hook up "editing changed" action for the text field to this method in IB
delegate?.cell(self, didUpdateTextField: sender)
}
}
现在,视图控制器将:
- 向相关 NIB 注册重用标识符;
- in
cellForRowAt
,填充文本字段并将其自身指定为该单元格的委托;和
- 处理
didUpdateTextField
如果用户更改任何内容,则更新模型的方法。
因此,类似:
class ViewController: UITableViewController {
var values = ["One", "Two", "Three"] // some initial values
private let cellIdentifier = "CustomCell"
override func viewDidLoad() {
super.viewDidLoad()
// if you’re using NIBs, you register them.
// obviously if using prototype cells in your storyboard, this isn’t necessary.
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: cellIdentifier) // or use cell prototype with storyboard identifer specified
}
}
// MARK: - UITableViewDataSource
extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return values.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! CustomCell
// populate cell and specify delegate
cell.delegate = self
cell.customTextField.text = values[indexPath.row]
return cell
}
}
// MARK: - CustomCellDelegate
extension ViewController: CustomCellDelegate {
func cell(_ cell: CustomCell, didUpdateTextField textField: UITextField) {
// when the cell tells us that its text field's value changed, update our own model
if let indexPath = tableView.indexPath(for: cell), let string = textField.text {
values[indexPath.row] = string
}
}
}
许多人可能倾向于通过挂钩来进一步简化这一点IBAction
将文本字段直接传递给视图控制器方法。这是可行的,并且消除了对此协议的需要,但问题是您需要弄清楚这个特定的 UIKit 控件与哪一行相关联。常见的技巧是向上导航视图层次结构以识别适当的单元格(例如,文本字段通常位于单元格内的内容视图中,因此您可以获取textField.superview.superview as! UITableViewCell
),但这对我来说有点脆弱。
但不管这个小细节如何,希望这能说明更广泛的模式。您应该让单元格(“视图”)立即更新任何数据更改的控制器,然后视图控制器立即更新模型,而不是尝试让单元格跟踪用户输入,您不再需要担心iOS 采用的单元重用优化。
对于 Swift 2 版本,请参阅此答案的先前修订版 https://stackoverflow.com/revisions/38272077/3.