TableViewCell中多UITextField滚动时值重复问题求助
解决UITableView滚动时UITextField值重复的问题
你遇到的问题是UITableView的cell复用机制导致的,再加上你用ArrayOfCell存储cell的方式存在错误,才会出现滚动时值重复、计算数据不准确的情况。下面我给你一步步拆解问题和解决方案:
问题根源
- Cell复用导致值残留:当UITableView滚动时,滚出屏幕的cell会被放入复用池,新进入屏幕的cell会复用这些旧cell。你没有在
cellForRowAt方法中为每个cell设置对应行的TextField值,所以复用的cell会显示之前输入的内容,造成"重复"现象。 - 存储cell数组的错误:
ArrayOfCell会不断添加复用的cell实例,数组里会有大量重复的cell对象,而且这些cell对应的行索引已经混乱,点击按钮计算时取到的根本不是每行的真实输入值。
正确解决方案
核心思路是把数据和UI分离:用数组存储每行的输入值,和你的化学品数据源一一对应;在cell复用的时候,从数组中取出对应索引的值填充到TextField;监听TextField的输入变化,实时更新数组中的数据;计算时直接遍历数据数组,而不是cell。
第一步:修正ViewController代码
import UIKit class Density_Price_Calculation_TableView: UIViewController, UITableViewDelegate, UITableViewDataSource { @IBOutlet weak var Density_Price_Calculation_TableView: UITableView! @IBOutlet weak var Gravity: UILabel! @IBOutlet weak var Price: UILabel! // 初始化数据数组,和化学品数据源长度一致,默认填充空字符串 private var phrValues = [String]() private var densityValues = [String]() private var priceValues = [String]() override func viewDidLoad() { super.viewDidLoad() Density_Price_Calculation_TableView.delegate = self Density_Price_Calculation_TableView.dataSource = self // 初始化数据数组,和化学品数量匹配 let chemicalCount = Density_Price_Chemicals_MasterData.instance.getChemical_Names().count phrValues = Array(repeating: "", count: chemicalCount) densityValues = Array(repeating: "", count: chemicalCount) priceValues = Array(repeating: "", count: chemicalCount) } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return Density_Price_Chemicals_MasterData.instance.getChemical_Names().count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "density_price_calculation_cell", for: indexPath) as! Density_Price_Calculation_TableViewCell let chemical = Density_Price_Chemicals_MasterData.instance.getChemical_Names()[indexPath.row] cell.updateViews(chemical_names: chemical) // 填充对应索引的输入值,解决复用残留问题 cell.phreditText.text = phrValues[indexPath.row] cell.densityeditText.text = densityValues[indexPath.row] cell.priceeditText.text = priceValues[indexPath.row] // 设置tag,方便在TextField代理中找到对应索引 cell.phreditText.tag = indexPath.row cell.densityeditText.tag = indexPath.row + 1000 // 避免tag重复 cell.priceeditText.tag = indexPath.row + 2000 // 设置TextField的代理,监听输入变化 cell.phreditText.delegate = self cell.densityeditText.delegate = self cell.priceeditText.delegate = self return cell } @IBAction func btn_pressed(_ sender: UIButton) { var totalSize = 0.00, gravity = 0.0, price = 0.0 // 遍历数据数组,而不是cell数组,确保数据准确 for i in 0..<phrValues.count { let tempPhr = Double(phrValues[i]) ?? 0 let tempDen = Double(densityValues[i]) ?? 0 let tempPrice = Double(priceValues[i]) ?? 0 totalSize += tempPhr if tempPhr != 0 && tempDen != 0 { gravity += tempPhr / tempDen } price += tempPhr * tempPrice } // 处理除以0的情况,避免崩溃 if totalSize != 0 && gravity != 0 { Gravity.text = String(format: "%.3f", totalSize / gravity) } else { Gravity.text = "0.000" } if totalSize != 0 { Price.text = String(format: "%.3f", price / totalSize) } else { Price.text = "0.000" } } } // 扩展实现UITextFieldDelegate,实时更新数据数组 extension Density_Price_Calculation_TableView: UITextFieldDelegate { func textFieldDidEndEditing(_ textField: UITextField) { guard let text = textField.text else { return } let index: Int // 根据tag判断是哪个TextField,找到对应行索引 switch textField.tag { case 0..<1000: index = textField.tag phrValues[index] = text case 1000..<2000: index = textField.tag - 1000 densityValues[index] = text case 2000..<3000: index = textField.tag - 2000 priceValues[index] = text default: return } } }
第二步:修正TableViewCell代码
不需要存储cell实例,去掉不必要的代码,同时可以优化键盘收起的逻辑:
import UIKit class Density_Price_Calculation_TableViewCell: UITableViewCell { @IBOutlet weak var chemical_name: UILabel! @IBOutlet weak var phreditText: UITextField! @IBOutlet weak var densityeditText: UITextField! @IBOutlet weak var priceeditText: UITextField! func updateViews(chemical_names:Density_Price_Calculation) { chemical_name.text = chemical_names.chemical_name } // 可以把键盘收起的逻辑移到ViewController,或者保持这里也可以 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) phreditText.resignFirstResponder() densityeditText.resignFirstResponder() priceeditText.resignFirstResponder() } }
关键改进点说明
- 数据与UI分离:用三个数组分别存储每行的PHR、密度、价格值,和化学品数据源一一对应,彻底摆脱对cell实例的依赖。
- 解决复用残留:在
cellForRowAt中为每个cell填充对应索引的输入值,确保滚动时显示的是当前行的正确数据。 - 实时更新数据:通过TextField代理监听输入结束事件,实时更新数据数组,保证数据和UI同步。
- 避免计算错误:计算时直接遍历数据数组,而不是cell数组,确保取到的是每行的真实输入值,不会因为cell复用导致数据混乱。
- 容错处理:添加了除以0的判断,避免计算时出现崩溃。
内容的提问来源于stack exchange,提问作者Bibhuranjan Bihari
相关产品推荐
相关产品推荐

