在UITableView中的自定义原型单元格中,UITextField值将replace为其他原型单元格

我采取了一个UITableView和里面,我已经使用了2个prototype单元格,现在在这些原型单元格中,我已经采取了1个UITextField

现在,当我运行应用程序,并在第一个原型单元格中input值,然后滚动UITableView ,然后第一个原型单元格的文本字段值来最后原型单元格的文本字段值。 所以它每次我滚动或滚动。 有时它变成空白。

这是我的代码

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { if(indexPath.row==0) { Client_MobileCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier_MobileCell forIndexPath:indexPath]; cell.lblTitle.text = [arrTitle objectAtIndex:indexPath.row]; cell.txtMobile.placeholder = [arrPlaceholder objectAtIndex:indexPath.row]; // cell.txtMobile.tag = indexPath.row+100; return cell; } else { // Client_Common_Cell *cell = (Client_Common_Cell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier_CommonCell forIndexPath:indexPath]; Client_Common_Cell *cell = (Client_Common_Cell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier_CommonCell]; // cell.txtCommon.tag = indexPath.row+100; cell.delegate = self; if(indexPath.row == 1 || indexPath.row == 2 || indexPath.row == 3 || indexPath.row == 4){ if(indexPath.row == 2) cell.txtCommon.secureTextEntry = YES; else if(indexPath.row == 4){ cell.txtCommon.keyboardType = UIKeyboardTypeEmailAddress; } cell.imgArrow.hidden = YES; cell.btnSelection.hidden = YES; } else{ cell.btnSelection.hidden = NO; cell.imgArrow.hidden = NO; } cell.lblTitle.text = [arrTitle objectAtIndex:indexPath.row]; cell.txtCommon.placeholder = [arrPlaceholder objectAtIndex:indexPath.row]; return cell; } 

}

当您使用dequeueReusableCellWithIdentifier ,您的单元格将被重用。 这意味着当用户滚动tableview ,移出屏幕的cell将被重新使用以显示将要移动到屏幕上的cell的内容。

尽pipe这有助于节省内存,但它造成的问题是,在加载新cell的内容之前, cell需要准备好显示。

在你的情况下,你似乎需要维护用户input到celltextfield中的值。

所以要解决你的问题,如果在tableview中没有那么多的cells ,只需停止重用cell (对每个单元实例使用alloc-init / new)。 从你的代码看起来你只有不到10个单元,这将是解决问题的最快方法。

否则,如果有大量的单元格,每当用户在celltextfield中input值时,将其保存在一个array 。 并从数组中获取值并将其设置到cellForRowAtIndexPath方法中的textfield中。

TL; DR(给我的代码)

Github链接: https : //github.com/starkindustries/CustomTableView

问题

正如其他人指出的, dequeueReusableCellWithIdentifier将在滚动时重用相同的单元格引用。 看看下面的gif,以便对这个问题进行直观的演示。

gif中的表格有20行(多行可以放在屏幕上)。 每行都有一个文本字段。 我把“一”,“二”,“三”,“四”分别放入第一到第四行。

正如你所看到的,当我向下滚动时,“两”,“三”和“一”神奇地出现在底部(不需要的行为)。 这是因为这些单元格在滚动屏幕时从顶端出队,并在底部再次被重用。

在这里输入图像说明

讨论

经过对Web和堆栈溢出的大量研究后,我build议您将文本字段的值存储在数组中。 然后,您可以在cellForRowAt方法中相应地设置文本字段文本。 @Rob完美地解释了如何在他的答案中使用模型 – 视图 – 控制器模式来解决这个问题: https ://stackoverflow.com/a/38272077/2179970。 我已经将这个build议应用到了这个例子中。

怎么运行的

  1. 首先,您将设置一个协议,以便自定义的UITableViewCell( 视图 )可以将消息发送回ViewController,以通知其文本字段已更改。 ViewController将执行该协议。 单元格将调用协议方法。
  2. 您的应用的用户将input文字。 这将触发自定义UITableViewCell类中的textFieldDidChange(_:)
  3. textFieldDidChange(_:)将调用TableViewController的委托方法cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField)来通知控制器文本已更改。
  4. 控制器将更新其文本数组( 模型 )以保存更改。
  5. cellForRowAt将更新单元格的文本字段的内容,如果需要重新使用。

解决scheme

协议:

 // Protocol from Step 1 protocol CustomCellDelegate: class { // This is the function that the ViewController will implement func cell(cell: UITableViewCell, updatedCustomTextField textField: UITextField) } 

自定义UITableViewCell:

 class MyTableViewCell: UITableViewCell, UITextFieldDelegate { // Protocol reference (Step 1) weak var delegate: CustomCellDelegate? @IBOutlet weak var textField: UITextField! override func awakeFromNib() { super.awakeFromNib() // Initialization code // (Step 2) Add a "textFieldDidChange" notification method to the text field control. textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControlEvents.editingChanged) } // Step 2 func textFieldDidChange(_ textField: UITextField) { delegate?.cell(cell: self, updatedCustomTextField: textField) } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } } 

视图控制器:

 class MyTableViewController: UITableViewController, CustomCellDelegate { var myTexts: [String?]! override func viewDidLoad() { super.viewDidLoad() myTexts = Array(repeating: nil, count: 20) let nib = UINib(nibName: "MyTableViewCell", bundle: nil) self.tableView.register(nib, forCellReuseIdentifier: "MyTableViewCell") } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { return 1 } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return 20 } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { print("CellForRowAt: " + indexPath.row.description) let cell = tableView.dequeueReusableCell(withIdentifier: "MyTableViewCell", for: indexPath) as! MyTableViewCell // Step 5: TableView updates cell contents if reused cell.delegate = self cell.textField.text = myTexts[indexPath.row] return cell } // MARK: - CustomCellDelegate Method // Step 3: The cell will call this protocol method to message the controller func cell(cell: UITableViewCell, updatedCustomTextField 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 { // Step 4: The controller updates the model: print("delegate method cell updatedCustomTextField") myTexts[indexPath.row] = string } } } 

结果

与前面一样,我在前四行中input了相同的“一”,“二”,“三”,“四” 这一次,表格的行为如预期的那样:文本字段的内容出现在我放置它们的地方,并且不会随机消失/出现。

在这里输入图像说明

Github链接

这里是项目的链接: https : //github.com/starkindustries/CustomTableView

参考

从nib初始化自定义的UITableViewCell,不带dequeueReusableCellWithIdentifier

UITableView中的UITextFields,input值重新出现在其他单元格中

UITableViewCell中的UITextField和模态视图中的validation