Swift动态TableView获取文本框值异常,多Section时数据错乱求解决
你遇到的问题核心在于**tableView.cellForRow(at:)只能获取当前屏幕可见的 Cell**,而不是所有逻辑上存在的 Cell。
当你的 TableView 有 4 个 Section 共 16 行时,大部分 Cell 其实并没有被实例化——TableView 为了性能优化,只会创建刚好填满屏幕的 Cell 数量。当你滚动时,离开屏幕的 Cell 会被放入复用池,新进入视野的 Cell 会从复用池取出并重新配置内容。这就导致你遍历所有 Section 和 Row 时:
- 不在屏幕上的 Cell,
cellForRow(at:)会返回nil - 甚至可能拿到被复用的、属于其他 Section/Row 的 Cell,这就会出现你看到的"Section 1 的值莫名变化"的情况
TableView 的设计理念是数据源驱动 UI,你应该始终维护一个和 TableView 结构对应的数据源数组,当用户在 TextField 输入内容时实时更新这个数组,需要获取所有值时直接读取数据源即可,完全不需要遍历 Cell。
步骤 1:定义数据源数组
首先在你的 ViewController 里定义一个二维数组,对应 Section 和 Row 的结构:
// 外层数组对应 Section,内层数组对应每个 Section 的 Row var tableViewDataSource: [[String]] = []
初始化时根据你的 Section 数量和每个 Section 的 Row 数量填充初始值(比如 4 个 Section,每个 Section 4 行):
// 假设每个 Section 有 4 行 finalSectionNumber = 4 tableViewDataSource = Array(repeating: Array(repeating: "", count: 4), count: finalSectionNumber)
步骤 2:在 Cell 输入时更新数据源
你需要监听 TextField 的输入事件,实时更新数据源。这里推荐用闭包的方式,避免 ViewController 和 Cell 之间的强耦合:
在 Cell 类里定义闭包,监听 TextField 内容变化:
class CellOutlet: UITableViewCell { @IBOutlet weak var txtFieldSpecNumb: UITextField! var onTextChanged: ((String?) -> Void)? override func awakeFromNib() { super.awakeFromNib() txtFieldSpecNumb.addTarget(self, action: #selector(textFieldChanged(_:)), for: .editingChanged) } @objc private func textFieldChanged(_ textField: UITextField) { onTextChanged?(textField.text) } }
然后在 cellForRowAt 方法里绑定闭包,同步更新数据源:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CellOutlet", for: indexPath) as! CellOutlet cell.txtFieldSpecNumb.text = tableViewDataSource[indexPath.section][indexPath.row] // 绑定闭包,实时更新数据源 cell.onTextChanged = { [weak self] text in guard let self = self else { return } self.tableViewDataSource[indexPath.section][indexPath.row] = text ?? "" } return cell }
步骤 3:修改 getAllValue 函数读取数据源
现在你只需要直接遍历数据源数组就能拿到所有正确的值:
func getAllValue() { for (sectionIndex, sectionData) in tableViewDataSource.enumerated() { print("section index: \(sectionIndex)") print("final txt field: \(finalSectionNumber)") for (rowIndex, value) in sectionData.enumerated() { print("row index: \(rowIndex)") print(value) } } }
这样无论你的 TableView 有多少个 Section 和 Row,都能准确获取所有输入的值,完全不会受到 Cell 复用机制的影响。
内容的提问来源于stack exchange,提问作者Aldo Sugiarto

