如何从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
- 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.
- Quantity Tracking: The cell now manages its own quantity state, so we can pass that value along with the item details.
- Temporary Cart Storage: We store cart items locally in
RestaurantViewControlleruntil the user decides to navigate to the cart. - 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

