Swift中使用UIStepper更新UITableViewCell内Label的问题求解
问题核心原因
你的代码存在两个核心错误导致数值不一致、stepper回弹的问题:
- cell初始化/复用时,没有同步
UIStepper的数值和FoodItem的serving值,stepper默认初始值为1,点击时就会从1开始计算,出现回弹 - 用
tag标记cell位置不可靠,cell滚动出屏幕复用时tag会变成旧值,代理回调时拿到的行索引错误,会更新错对应行的label
具体修改方案
第一步:修改FoodTableViewCell代码
import UIKit protocol FoodTableViewCellDelegate: AnyObject { // 直接把cell本身作为参数传递,不用依赖tag func stepper(in cell: FoodTableViewCell, didChangeValueTo newValue: Double) } class FoodTableViewCell: UITableViewCell { @IBOutlet weak var nameLabel: UILabel! @IBOutlet weak var priceLabel: UILabel! @IBOutlet weak var servingLabel: UILabel! @IBOutlet weak var stepper: UIStepper! weak var delegate: FoodTableViewCellDelegate? @IBAction func stepperValueChanged(_ sender: UIStepper) { servingLabel.text = "\(String(format: "%.0f", sender.value)) serving" delegate?.stepper(in: self, didChangeValueTo: sender.value) } override func awakeFromNib() { super.awakeFromNib() // 最小值只需要初始化时设置一次即可,不用每次触发事件都设置 stepper.minimumValue = 1 } // 新增统一的cell配置方法,避免VC里写大量UI赋值逻辑 func configure(with food: FoodItem) { nameLabel.text = food.name priceLabel.text = "$\(food.price) / serving" servingLabel.text = "\(food.serving) serving" // 关键:同步stepper的数值为当前食物的实际份数 stepper.value = Double(food.serving) } }
第二步:修改ShoppingListVC代码
import UIKit class ShoppingListVC: UIViewController, UITableViewDataSource, UITableViewDelegate { var foodList = [FoodItem]() @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() tableView.delegate = self tableView.dataSource = self // 你的其他原有逻辑 for i in 1...5 { let testItem = FoodItem(name: "Food\(i)", price: Int.random(in: 60...100), serving: Int.random(in: 1...10)) self.foodList.append(testItem) } } // MARK: - Table view data source func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return foodList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "foodCell", for: indexPath) as! FoodTableViewCell // 调用配置方法赋值,逻辑更清晰 cell.configure(with: foodList[indexPath.row]) cell.delegate = self return cell } } // MARK: - FoodTableViewCellDelegate Method. extension ShoppingListVC: FoodTableViewCellDelegate { func stepper(in cell: FoodTableViewCell, didChangeValueTo newValue: Double) { // 从cell反查正确的indexPath,完全规避tag失效的问题 guard let indexPath = tableView.indexPath(for: cell) else { return } // 更新模型数据 foodList[indexPath.row].serving = Int(newValue) // 刷新对应行即可,不需要手动修改cell的label,保证UI和模型完全同步 tableView.reloadRows(at: [indexPath], with: .none) } }
内容的提问来源于stack exchange,提问作者Judy Tsai
相关产品推荐
相关产品推荐

