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

如何从RestaurantViewController传值到自定义Cell并同步含数量数据至CartVC

Hey there! Let's work through this problem step by step—your final project is counting on it, so let's get this right.

The core issue with your current setup is that you're triggering the block when the cell loads, not when the user actually taps the "add" button after adjusting the quantity. Plus, you weren't even passing the quantity value at all! Here's how to fix this properly:

Step 1: Refactor Your Custom Cell

First, update your custom cell class to hold the item details, track the current quantity, and only trigger the data transfer when the "add" button is tapped.

class CustomMenuCell: UITableViewCell {
    // Your existing UI outlets
    @IBOutlet weak var itemNameLabel: UILabel!
    @IBOutlet weak var itemPriceLabel: UILabel!
    @IBOutlet weak var quantityLabel: UILabel! // Add a label to show current quantity
    
    // Internal state for the cell
    private var currentQuantity = 0
    private var itemName: String = ""
    private var itemPrice: String = "" // Use Double if you plan to calculate totals later
    
    // Define a closure that passes the full item data (name, price, quantity)
    var addToCartAction: ((String, String, Int) -> Void)?

    // Helper method to configure the cell with menu item data
    func setup(withItemName name: String, price: String) {
        itemName = name
        itemPrice = price
        currentQuantity = 0
        
        // Update UI
        itemNameLabel.text = name
        itemPriceLabel.text = "Price: \(price)"
        quantityLabel.text = "\(currentQuantity)"
    }

    // + Button Action
    @IBAction func plusButtonTapped(_ sender: UIButton) {
        currentQuantity += 1
        quantityLabel.text = "\(currentQuantity)"
    }

    // - Button Action
    @IBAction func minusButtonTapped(_ sender: UIButton) {
        guard currentQuantity > 0 else { return } // Prevent negative quantity
        currentQuantity -= 1
        quantityLabel.text = "\(currentQuantity)"
    }

    // Add Button Action (THIS IS WHERE WE TRIGGER DATA TRANSFER)
    @IBAction func addButtonTapped(_ sender: UIButton) {
        guard currentQuantity > 0 else {
            // Optional: Show an alert to tell the user to select a quantity first
            return
        }
        
        // Pass the full data to the parent view controller via closure
        addToCartAction?(itemName, itemPrice, currentQuantity)
        
        // Optional: Reset quantity after adding to cart
        currentQuantity = 0
        quantityLabel.text = "\(currentQuantity)"
    }
}

Step 2: Update RestaurantViewController

Now, modify your RestaurantViewController to handle the closure from the cell, store the cart data temporarily, and only pass it to CartVC when the shopping cart icon is tapped.

class RestaurantViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    @IBOutlet weak var tableView: UITableView!
    var restMenu: [NSDictionary] = [] // Your existing menu data
    // Temporary storage for cart items (use a custom model instead of tuples for better code)
    private var cartItems: [(name: String, price: String, quantity: Int)] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        tableView.delegate = self
        tableView.register(UINib(nibName: "CustomMenuCell", bundle: nil), forCellReuseIdentifier: "CustomMenuCell")
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return restMenu.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CustomMenuCell", for: indexPath) as! CustomMenuCell
        let menuItem = restMenu[indexPath.row] as NSDictionary
        
        let itemName = menuItem.value(forKey: "ItemName") as! String
        let itemPrice = menuItem.value(forKey: "ItemPrice") as! String
        
        // Configure the cell with item data
        cell.setup(withItemName: itemName, price: itemPrice)
        
        // Set up the closure to capture cart data when "add" is tapped
        cell.addToCartAction = { [weak self] name, price, quantity in
            guard let self = self else { return }
            
            // Check if the item is already in the cart—update quantity if so
            if let existingIndex = self.cartItems.firstIndex(where: { $0.name == name }) {
                var existingItem = self.cartItems[existingIndex]
                existingItem.quantity += quantity
                self.cartItems[existingIndex] = existingItem
            } else {
                // Add new item to cart
                self.cartItems.append((name: name, price: price, quantity: quantity))
            }
            
            // Optional: Update cart icon badge with total item count
            // self.updateCartBadge(count: self.cartItems.reduce(0) { $0 + $1.quantity })
        }

        return cell
    }

    // Shopping Cart Icon Tap Action
    @IBAction func cartIconTapped(_ sender: UIBarButtonItem) {
        // Navigate to CartVC and pass the stored cart data
        guard let cartVC = storyboard?.instantiateViewController(withIdentifier: "CartVC") as? CartVC else { return }
        cartVC.cartItems = self.cartItems
        navigationController?.pushViewController(cartVC, animated: true)
    }
}

Step 3: Prepare CartVC to Receive Data

Finally, update CartVC to display the received cart data:

class CartVC: UIViewController, UITableViewDataSource {
    @IBOutlet weak var cartTableView: UITableView!
    var cartItems: [(name: String, price: String, quantity: Int)] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        cartTableView.dataSource = self
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cartItems.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CartCell", for: indexPath)
        let item = cartItems[indexPath.row]
        
        cell.textLabel?.text = item.name
        // Calculate total for the item (convert price to Double if needed)
        let itemTotal = Double(item.price)! * Double(item.quantity)
        cell.detailTextLabel?.text = "\(item.quantity) x \(item.price) = $\(String(format: "%.2f", itemTotal))"
        
        return cell
    }
}

Key Improvements Over Your Original Code

  1. Data Transfer Timing: We only send data to the parent view controller when the user taps "add" (after setting quantity), not when the cell loads.
  2. Quantity Tracking: The cell now manages its own quantity state, so we can pass that value along with the item details.
  3. Temporary Cart Storage: We store cart items locally in RestaurantViewController until the user decides to navigate to the cart.
  4. Cart Item Updates: We check for existing items in the cart and update their quantity instead of adding duplicates.

Pro Tip

For cleaner, safer code, replace the tuples and NSDictionary with custom models like:

struct MenuItem {
    let name: String
    let price: Double
}

struct CartItem {
    let menuItem: MenuItem
    var quantity: Int
}

This eliminates forced unwrapping and makes your code more maintainable.

内容的提问来源于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.27 07:15:29