2

When I click on “Add” Button below, the products do not get added to the cart and the Checkout (0) does not increase to Checkout (1) etc. What am I doing wrong ?

-- Original issue resolved after reading @Larme's first comment. It was a rookie mistake(I had forgotten to put cell.delegate = self in tableView(_ tableView:, cellForRowAt: in ProductViewController). Now, I have some other problemin CartViewController(See Edit please) --

enter image description here

posting relevant code -

struct Product -

import UIKit

 struct Product:Equatable {
let name : String
var quantity : Int
var price : Double
let imagename: UIImage
 // var subTotal : Double {
   //return Double(quantity) * price }
}

var products = [Product(name: "a", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "PeasImge")),
                Product(name: "b", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "CakeImage")),]

class ProductViewController -

import UIKit

class ProductViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    fileprivate var cart = Cart()

    @IBOutlet weak var tableView: UITableView!
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self    }

        override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        //Workaround to avoid the fadout the right bar button item
        self.navigationItem.rightBarButtonItem?.isEnabled = false
        self.navigationItem.rightBarButtonItem?.isEnabled = true

        //Update cart if some items quantity is equal to 0 and reload the product table and right button bar item

        cart.updateCart()
        self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
        tableView.reloadData()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    /*   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "showCart" {
            if let cartViewController = segue.destination as? CartViewController {
                cartViewController.cart = self.cart
            }
        }
    }*/

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return products.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell   {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ProductTableViewCell") as!   ProductTableViewCell



        let product = products[indexPath.item] 
       cell.delegate = self // original issue was here, now resolved.
       cell.name?.text = product.name
        cell.imageView?.image =  product.imagename
        cell.setButton(state: self.cart.contains(product: product))
        // Configure YourCustomCell using the outlets that you've defined.

        return cell
    }
}

extension ProductViewController: CartDelegate {

    // MARK: - CartDelegate
    func updateCart(cell: ProductTableViewCell) {
        guard let indexPath = tableView.indexPath(for: cell) else { return }
        let product = products[indexPath.item]

        //Update Cart with product
        cart.updateCart(with: product)
        self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
    }
}

class ProductTableViewCell-

import UIKit
  
protocol CartDelegate {
    func updateCart(cell: ProductTableViewCell)
}

class ProductTableViewCell: UITableViewCell {
    weak var myParent:ProductViewController?
    @IBOutlet weak var name: UILabel!
    @IBOutlet weak var price: UILabel!
    @IBOutlet weak var imagename: UIImageView!

    @IBOutlet weak var addToCartButton: UIButton!




    var delegate: CartDelegate?

    override func awakeFromNib() {
    super.awakeFromNib()
        // Initialization code

        addToCartButton.layer.cornerRadius = 5
        addToCartButton.clipsToBounds = true
    }

    func setButton(state: Bool) {
        addToCartButton.isSelected = state
        addToCartButton.backgroundColor = (!addToCartButton.isSelected) ? .black : .red
    }

    @IBAction func addToCart(_ sender: Any) {
        setButton(state: !addToCartButton.isSelected)
        self.delegate?.updateCart(cell: self)
    }
}

class CartItem

import Foundation

 class CartItem {
 var quantity : Int = 1
 var product : Product
/*  var subTotal : Float { get { return Float(product.price) *     Float(quantity) } } */
 init(product: Product) {
    self.product = product
  }
}

class Cart -

  import Foundation

 class Cart {
  var items : [CartItem] = []
  }

extension Cart {


 /* var total: Float {
    get { return items.reduce(0.0) { value, item in
        value + item.subTotal
        }
    }
 }*/

var totalQuantity : Int {
    get { return items.reduce(0) { value, item in
        value + item.quantity
        }
    }
}
func updateCart(with product: Product) {
    if !self.contains(product: product) {
        self.add(product: product)
    } else {
        self.remove(product: product)
    }
}
func updateCart() {
    
    for item in self.items {
        if item.quantity == 0 {
            updateCart(with: item.product)
        }
      }
    }

func add(product: Product) {
    let item = items.filter { $0.product == product }
    
    if item.first != nil {
        item.first!.quantity += 1
      } else {
        items.append(CartItem(product: product))
     }
   }

  func remove(product: Product) {
    guard let index = items.firstIndex(where: { $0.product == product }) else { return}
    items.remove(at: index)
}
func contains(product: Product) -> Bool {
    let item = items.filter { $0.product == product }
    return item.first != nil
 }

}

I can also post “CartItemTableViewCell” and “CartViewController” if you will.

Any help would be greatly appreciated.

Edit: The original issue is resolved now, thanks to @Larme.

I have another issue for which I have pasted “CartViewController” and “CartItemTableViewCell” as well along with some rectifications in the old code after reading @Larme's first comment.

The issue is in CartViewController - When I click on Checkout button after loading the cart, it shows error in CartviewController's "tableView(_ tableView: UITableView, numberOfRowsInSection" - see CartVieController code below:-

class CartViewController

 import UIKit

class CartViewController: UIViewController {
@IBOutlet weak var tableView: UITableView!
@IBOutlet weak var totalView: UIView!
@IBOutlet weak var totalLabel: UILabel!

var cart: Cart? = nil
fileprivate let reuseIdentifier = "CartItemCell"
override func viewDidLoad() {
    super.viewDidLoad()
    tableView.tableFooterView = UIView(frame: .zero)
   }
 }

extension CartViewController: UITableViewDelegate, UITableViewDataSource {
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
    // #warning Incomplete implementation, return the number of sections
    return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // #warning Incomplete implementation, return the number of rows
   return (cart?.items.count)!// Error - Thread 1:EXC_BAD_INSTRUCTION..
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! CartItemTableViewCell
    
   if let cartItem = cart?.items[indexPath.item] {
        cell.delegate = self as CartItemDelegate
        
        cell.nameLabel.text = cartItem.product.name
     //   cell.priceLabel.text = cartItem.product.price
        cell.quantityLabel.text = String(describing: cartItem.quantity)
        
        
        
       cell.quantity = cartItem.quantity
        // cell.contentView.backgroundColor = !cell.decrementButton.isEnabled ? .white : .blue
    }
    return cell
        }
      }

 extension CartViewController: CartItemDelegate {

// MARK: - CartItemDelegate
func updateCartItem(cell: CartItemTableViewCell, quantity: Int) {
    guard let indexPath = tableView.indexPath(for: cell) else { return      }
    guard let cartItem = cart?.items[indexPath.row] else { return }
    
    //Update cart item quantity
    cartItem.quantity = quantity
    
    //Update displayed cart total
 //   guard let total = cart?.total else { return }
    
    //totalLabel.text = String(total)
    //   print(total)
    }
  }

class CartItemTableViewCell -

import UIKit

 protocol CartItemDelegate {
func updateCartItem(cell: CartItemTableViewCell, quantity: Int)
}

class CartItemTableViewCell: UITableViewCell {

@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var priceLabel: UILabel!

@IBOutlet weak var incrementButton: UIButton!
@IBOutlet weak var decrementButton: UIButton!
@IBOutlet weak var quantityLabel: UILabel!

var delegate: CartItemDelegate?
var quantity: Int = 1

 override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
    
    incrementButton.layer.cornerRadius = 10
    incrementButton.clipsToBounds = true
    
    decrementButton.layer.cornerRadius = 10
    decrementButton.clipsToBounds = true
  }

 override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
 }

   @IBAction func updateCartItemQuantity(_ sender: Any) {
    if (sender as! UIButton).tag == 0 {
        quantity = quantity + 1
    } else if quantity > 0 {
        quantity = quantity - 1
    }
    
    decrementButton.isEnabled = quantity > 0
    decrementButton.backgroundColor = !decrementButton.isEnabled ? .gray : .black
    
    self.quantityLabel.text = String(describing: quantity)
    self.delegate?.updateCartItem(cell: self, quantity: quantity)
  }
}






  
askit
  • 205
  • 4
  • 21
  • `self.delegate?.updateCart(cell: self)` is called, but `self.delegate` is `nil`, since you didn't set it, no?. Could you check if that's like that? That's how you start debugging. Then, you'll add `cell.delegate = self` in `tableView(_ tableView:, cellForRowAt: )`. – Larme Sep 09 '20 at 07:55
  • @Larme - yes, you are sharp, I had somehow missed cell.delegate = self in tableView(_ tableView:, cellForRowAt: ) in ProductViewController., but now when I click on Checkout(0), its shows one more error in CartViewController(please see edit). Another rookie mistake? – askit Sep 10 '20 at 09:11
  • @Larme - you have helped me to solve the oiginal issue.. I would be delighted to upvote and mark this as right answer if you post this as an answer. Also, if you can go an extra mile and see the supplementary of this question here - https://stackoverflow.com/q/63956420/7444874 , it would mean a lot to me. Thanks. – askit Sep 18 '20 at 13:16

0 Answers0