iOS Swift:滚动UITableView时ItemQuantityCell值重置,如何更新restMenu?
解决UITableView滚动时ItemQuantityCell数值复用默认值的问题
你遇到的核心问题是UITableView的单元格复用机制导致的:当滚动表格时,系统会复用已经移出屏幕的单元格,而你当前只在cellForRowAt里读取restMenu的初始默认值,却没有把用户修改后的数量同步回restMenu,所以每次复用单元格时,又会显示原始的0值。下面是一步步的解决方案:
1. 给单元格添加数量变化的回调机制
首先需要让RestaurantItemViewCell能在数量改变时通知视图控制器,这里用代理模式实现:
// 在RestaurantItemViewCell中定义代理协议 protocol RestaurantItemCellDelegate: AnyObject { func itemQuantityUpdated(at index: Int, to newQuantity: Int) } class RestaurantItemViewCell: UITableViewCell { weak var delegate: RestaurantItemCellDelegate? var currentIndexPath: IndexPath? // 记录当前单元格对应的索引 // 假设你用加号按钮增加数量 @IBAction func plusButtonTapped(_ sender: UIButton) { guard let currentQuantText = itemQuantityLabel.text, var currentQuant = Int(currentQuantText), let row = currentIndexPath?.row else { return } currentQuant += 1 itemQuantityLabel.text = "\(currentQuant)" // 通知控制器更新数据 delegate?.itemQuantityUpdated(at: row, to: currentQuant) } // 减号按钮同理,注意防止数量为负 @IBAction func minusButtonTapped(_ sender: UIButton) { guard let currentQuantText = itemQuantityLabel.text, var currentQuant = Int(currentQuantText), let row = currentIndexPath?.row else { return } if currentQuant > 0 { currentQuant -= 1 itemQuantityLabel.text = "\(currentQuant)" delegate?.itemQuantityUpdated(at: row, to: currentQuant) } } // 其他现有代码... }
2. 在视图控制器中实现代理,同步更新restMenu
让restaurantViewController遵循代理协议,把用户修改后的数量实时存回restMenu:
class RestaurantViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, RestaurantItemCellDelegate { var restMenu = [[String:Any]]() // 实现代理方法,更新数据源 func itemQuantityUpdated(at index: Int, to newQuantity: Int) { // 根据plist里的类型选择存储方式:如果是字符串就转成String,是数字就存Int restMenu[index]["ItemQuant"] = "\(newQuantity)" // 如果plist里ItemQuant是Number类型,改成 restMenu[index]["ItemQuant"] = newQuantity } // 其他现有代码... }
3. 优化cellForRowAt方法,确保复用单元格读取最新值
修改cellForRowAt,给单元格传递索引,并且每次复用都从restMenu读取最新的数量:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RestaurantItemViewCell cell.delegate = self cell.selectionStyle = .none cell.currentIndexPath = indexPath // 传递当前索引 let menuItem = restMenu[indexPath.row] // 设置商品名称 cell.itemNameLabel.text = menuItem["ItemName"] as? String // 设置商品价格 if let price = menuItem["ItemPrice"] as? String { cell.itemPriceLabel.text = "Price: \(price)" } // 设置最新数量——这里一定要取restMenu的当前值,而非默认值 let currentQuantity = menuItem["ItemQuant"] as? String ?? "0" cell.itemQuantityLabel.text = currentQuantity return cell }
4. 传递更新后的restMenu到checkoutVC
当跳转到结算页面时,直接传递已经更新好的restMenu即可:
// 假设用segue跳转 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "toCheckout" { guard let checkoutVC = segue.destination as? CheckoutViewController else { return } checkoutVC.selectedMenuItems = restMenu // 传递最新数据 } }
额外注意点
- 统一数据类型:如果你的plist里
ItemQuant是数字类型(Number),建议在代码里用Int处理,避免字符串和数字转换出错,比如读取时用menuItem["ItemQuant"] as? Int ?? 0,设置label时转成String(currentQuantity)。 - 如果用UITextField输入数量,要在编辑结束时同步更新
restMenu,并且限制输入只能是数字。
这样修改后,用户调整的数量会实时同步到restMenu,滚动表格时复用的单元格会读取最新值,不会再回到默认0,最后传递到结算页的也是正确的数值。
内容的提问来源于stack exchange,提问作者Gurjit Singh
相关产品推荐
相关产品推荐

