UITableViewCell中UISwitch触发其他开关联动异常问题咨询
Hey there, this is a classic UITableView cell reuse issue—the reason your 1st and 11th cells in the second section are syncing their switch states is because they're actually using the same instance of your custom cell from the reuse pool. The "11" connection makes sense here: with 6 cells in the first section, once you scroll far enough to reach the 11th cell in the second section, the first cell of that section has likely scrolled off-screen and gets pulled back out of the reuse pool for the 11th cell. Without proper state management, the switch's state and event bindings carry over.
Here's how to fix it step by step:
1. Use a Data Model to Track Switch States
Never rely on the cell's UI components to store state—you need a dedicated data structure to track each switch's on/off status. For your two-section setup, a 2D array works perfectly:
// Initialize with default false state: 6 cells in section 0, 11 in section 1 var switchStates: [[Bool]] = [ Array(repeating: false, count: 6), Array(repeating: false, count: 11) ]
2. Correctly Configure Cells in cellForRowAt
When dequeuing a reusable cell, you must explicitly set its state from the data model, and clear old event bindings to prevent duplicate triggers. Here's how to do it:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "YourCustomCellID", for: indexPath) as! YourCustomSwitchCell // First, clear any existing target-action or closures to avoid old callbacks firing cell.switchControl.removeTarget(nil, action: nil, for: .valueChanged) cell.onSwitchToggle = nil // If using a closure-based setup // Set the switch state from our data model let currentState = switchStates[indexPath.section][indexPath.row] cell.switchControl.isOn = currentState // Bind the switch's change event to update our data model cell.onSwitchToggle = { [weak self] isOn in guard let self = self else { return } self.switchStates[indexPath.section][indexPath.row] = isOn // If you actually wanted to sync specific cells (but you said this is an exception, so skip this line) // tableView.reloadRows(at: [IndexPath(row: targetRow, section: targetSection)], with: .automatic) } return cell }
3. Clean Up Cells Before Reuse
Update your custom cell class to reset its state when it's prepared for reuse—this ensures no leftover state or bindings carry over to the next cell that uses it:
class YourCustomSwitchCell: UITableViewCell { @IBOutlet weak var switchControl: UISwitch! var onSwitchToggle: ((Bool) -> Void)? override func prepareForReuse() { super.prepareForReuse() // Reset switch state and clear closure switchControl.isOn = false onSwitchToggle = nil // Also clear any target-action bindings if you're using that approach switchControl.removeTarget(nil, action: nil, for: .valueChanged) } @IBAction func switchValueChanged(_ sender: UISwitch) { onSwitchToggle?(sender.isOn) } }
Why Does This Happen With the 11th Cell?
UITableView maintains a small pool of reusable cells to optimize performance. When the first cell of the second section scrolls off-screen, it gets added to the pool. By the time you reach the 11th cell in that section, the table view pulls that same cell instance from the pool to reuse. Since you weren't resetting the switch state or clearing old callbacks, the new cell inherits the previous cell's switch behavior.
内容的提问来源于stack exchange,提问作者Alex Ritter

