You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:24:42