Click here to Skip to main content
15,890,123 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
The issue is in CartViewController - When I click on "Checkout(2)" rightBarButtonItem in the ProductViewController, it shows error in CartviewController's "numberOfRowsInSection" function - Kindly see image & codes below:-

I have been ruminating over for quite some time. Please save my skin.
Detailed link to the problem is here :- uitableview - swift data not transferred from UIBarButtonItem to another viewcontroller - Stack Overflow[^]

What I have tried:

Swift
  1  class ProductViewController -
  2  
  3    import UIKit
  4    
  5    class ProductViewController: UIViewController, UITableViewDataSource,   UITableViewDelegate {
  6  let sections = ["Section A", "Section B"]
  7  let rowspersection = [3,1]
  8  fileprivate var cart = Cart()
  9  
 10   @IBOutlet weak var tableView: UITableView!
 11   override func viewDidLoad() {
 12      super.viewDidLoad()
 13      tableView.delegate = self
 14      tableView.dataSource = self    
 15      }
 16  
 17  override func viewWillAppear(_ animated: Bool) {
 18      super.viewWillAppear(animated)
 19      
 20      //Workaround to avoid the fadout the right bar button item
 21      self.navigationItem.rightBarButtonItem?.isEnabled = false
 22      self.navigationItem.rightBarButtonItem?.isEnabled = true
 23      
 24      //Update cart if some items quantity is equal to 0 and reload the product table   and right button bar item
 25      
 26      cart.updateCart()
 27     self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
 28      tableView.reloadData()
 29   }
 30  
 31   override func didReceiveMemoryWarning() {
 32      super.didReceiveMemoryWarning()
 33      // Dispose of any resources that can be recreated.
 34  }
 35   override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
 36   if segue.identifier == "showCart" {
 37   if let cartViewController = segue.destination as? CartViewController {
 38   cartViewController.cart = self.cart
 39       }
 40     }
 41   }
 42  
 43  func numberOfSections(in tableView: UITableView) -> Int {
 44      return sections.count
 45   }
 46  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 47      return rowspersection[section]
 48   }
 49  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell   {
 50      let cell = tableView.dequeueReusableCell(withIdentifier: "ProductTableViewCell") as!   ProductTableViewCell
 51      cell.delegate = self // original issue was here, now resolved.
 52     
 53      var index = indexPath.row
 54      if indexPath.section != 0, rowspersection.count > indexPath.section - 1{
 55          index += rowspersection[indexPath.section - 1]
 56      }
 57      
 58    if index < productarray.count{
 59          let data = productarray[index]
 60       cell.name?.text = data.name
 61          cell.imageView?.image =  data.imagename
 62    }
 63       let product = productarray[indexPath.item]
 64       cell.setButton(state: self.cart.contains(product: product))
 65      return cell
 66     }
 67  func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
 68      return 44
 69    }
 70  
 71  func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
 72      switch(section) {
 73      case 0:return "Section A"
 74      case 1:return "Section B"
 75      default :return ""
 76          
 77        }
 78      }
 79    }
 80  
 81   extension ProductViewController: CartDelegate {
 82  
 83  // MARK: - CartDelegate
 84  func updateCart(cell: ProductTableViewCell) {
 85      guard let indexPath = tableView.indexPath(for: cell) else { return }
 86      let product = productarray[indexPath.item]
 87      
 88      //Update Cart with product
 89      cart.updateCart(with: product)
 90      self.navigationItem.rightBarButtonItem?.title = "Checkout (\(cart.items.count))"
 91     }
 92   }
The issue is in CartViewController - When I click on "Checkout(2)" rightBarButtonItem in the ProductViewController(see image above), it shows error in CartviewController's "numberOfRowsInSection" function - see CartViewController code below:-
Swift
  1   import UIKit
  2   
  3   class CartViewController: UIViewController {
  4   @IBOutlet weak var tableView: UITableView!
  5   @IBOutlet weak var totalView: UIView!
  6   @IBOutlet weak var totalLabel: UILabel!
  7  
  8   var cart: Cart? = nil
  9  fileprivate let reuseIdentifier = "CartItemCell"
 10  override func viewDidLoad() {
 11      super.viewDidLoad()
 12      tableView.tableFooterView = UIView(frame: .zero)
 13    }
 14   }
 15  
 16  extension CartViewController: UITableViewDelegate, UITableViewDataSource {
 17  // MARK: - Table view data source
 18  func numberOfSections(in tableView: UITableView) -> Int {
 19      // #warning Incomplete implementation, return the number of sections
 20      return 1
 21  }
 22  func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 23      // #warning Incomplete implementation, return the number of rows
 24      return (cart?.items.count)!  /*Error - Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)*/
 25  }
 26  
 27  func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
 28    let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! CartItemTableViewCell
 29      
 30   if let cartItem = cart?.items[indexPath.item] {
 31   cell.delegate = self as CartItemDelegate
 32          
 33        //  cell.nameLabel.text = cartItem.product.name
 34       //   cell.priceLabel.text = cartItem.product.price
 35          cell.quantityLabel.text = String(describing: cartItem.quantity)
 36          
 37        cell.quantity = cartItem.quantity
 38          // cell.contentView.backgroundColor = !cell.decrementButton.isEnabled ? .white : .blue
 39      }
 40      return cell
 41    }
 42  }
 43  
 44  
 45   extension CartViewController: CartItemDelegate {
 46  
 47  // MARK: - CartItemDelegate
 48  func updateCartItem(cell: CartItemTableViewCell, quantity: Int) {
 49      guard let indexPath = tableView.indexPath(for: cell) else { return }
 50      guard let cartItem = cart?.items[indexPath.row] else { return }
 51      
 52      //Update cart item quantity
 53      cartItem.quantity = quantity
 54      
 55      //Update displayed cart total
 56   //   guard let total = cart?.total else { return }
 57      //totalLabel.text = String(total)
 58      //   print(total)
 59      }
 60    }

My Models -
Swift
  1  struct Product -
  2  
  3   import UIKit
  4   
  5   struct Product:Equatable {
  6   let name : String
  7   var quantity : Int
  8   var price : Double
  9   let imagename: UIImage
 10     // var subTotal : Double {
 11      //return Double(quantity) * price }
 12   }
 13   var productarray = [Product(name: "a", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "CakeImage")),
 14    Product(name: "b", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "PeasImge")),Product(name: "a", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "vectorlogo")),
 15                  Product(name: "b", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "blue")),]
 16  
 17  class CartItem -
 18  
 19  import Foundation
 20  
 21  class CartItem {
 22  var quantity : Int = 1
 23  var product : Product
 24  // var subTotal : Float { get { return Float(product.price) * Float(quantity) } }
 25  init(product: Product) {
 26      self.product = product
 27    }
 28  }
 29  
 30  class Cart -
 31  
 32    import Foundation
 33  
 34    class Cart {
 35    var items : [CartItem] = []
 36    }
 37  
 38  extension Cart {
 39  
 40     /* var total: Float {
 41      get { return items.reduce(0.0) { value, item in
 42          value + item.subTotal
 43          }
 44      }
 45   }*/
 46  
 47    var totalQuantity : Int {
 48      get { return items.reduce(0) { value, item in
 49          value + item.quantity
 50          }
 51      }
 52   }
 53  func updateCart(with product: Product) {
 54      if !self.contains(product: product) {
 55          self.add(product: product)
 56      } else {
 57          self.remove(product: product)
 58      }
 59  }
 60  func updateCart() {
 61      
 62      for item in self.items {
 63          if item.quantity == 0 {
 64              updateCart(with: item.product)
 65          }
 66      }
 67  }
 68  
 69  func add(product: Product) {
 70      let item = items.filter { $0.product == product }
 71      
 72      if item.first != nil {
 73          item.first!.quantity += 1
 74      } else {
 75          items.append(CartItem(product: product))
 76      }
 77  }
 78  
 79  func remove(product: Product) {
 80      guard let index = items.firstIndex(where: { $0.product == product }) else { return}
 81      items.remove(at: index)
 82  }
 83  
 84  
 85  func contains(product: Product) -> Bool {
 86      let item = items.filter { $0.product == product }
 87      return item.first != nil
 88     }
 89   }
The UITableViewCells -
Swift
  1  class ProductTableViewCell -
  2  
  3   import UIKit
  4   protocol CartDelegate {
  5   func updateCart(cell: ProductTableViewCell) }
  6   class ProductTableViewCell: UITableViewCell {
  7   weak var myParent:ProductViewController?
  8   @IBOutlet weak var name: UILabel!
  9   @IBOutlet weak var price: UILabel!
 10   @IBOutlet weak var imagename: UIImageView!
 11   @IBOutlet weak var addToCartButton: UIButton!
 12  
 13   var delegate: CartDelegate?
 14  
 15   override func awakeFromNib() {
 16      super.awakeFromNib()
 17      // Initialization code
 18      
 19     addToCartButton.layer.cornerRadius = 5
 20    addToCartButton.clipsToBounds = true
 21   }
 22  
 23    func setButton(state: Bool) {
 24      addToCartButton.isSelected = state
 25      addToCartButton.backgroundColor = (!addToCartButton.isSelected) ? .black : .red
 26  }
 27  
 28     @IBAction func addToCart(_ sender: Any) {
 29      setButton(state: !addToCartButton.isSelected)
 30      self.delegate?.updateCart(cell: self)
 31      }
 32    }
 33  
 34  class CartItemTableViewCell-
 35  
 36   import UIKit
 37   
 38   protocol CartItemDelegate {
 39   func updateCartItem(cell: CartItemTableViewCell, quantity: Int)
 40   }
 41   class CartItemTableViewCell: UITableViewCell {
 42  
 43  @IBOutlet weak var nameLabel: UILabel!
 44  @IBOutlet weak var priceLabel: UILabel!
 45  
 46  @IBOutlet weak var incrementButton: UIButton!
 47  @IBOutlet weak var decrementButton: UIButton!
 48  @IBOutlet weak var quantityLabel: UILabel!
 49  
 50  var delegate: CartItemDelegate?
 51  var quantity: Int = 1
 52  
 53  override func awakeFromNib() {
 54      super.awakeFromNib()
 55      // Initialization code
 56      
 57      incrementButton.layer.cornerRadius = 10
 58      incrementButton.clipsToBounds = true
 59      
 60      decrementButton.layer.cornerRadius = 10
 61      decrementButton.clipsToBounds = true
 62   }
 63  
 64  override func setSelected(_ selected: Bool, animated: Bool) {
 65      super.setSelected(selected, animated: animated)
 66   }
 67  
 68  @IBAction func updateCartItemQuantity(_ sender: Any) {
 69      if (sender as! UIButton).tag == 0 {
 70          quantity = quantity + 1
 71      } else if quantity > 0 {
 72          quantity = quantity - 1
 73      }
 74      
 75      decrementButton.isEnabled = quantity > 0
 76      decrementButton.backgroundColor = !decrementButton.isEnabled ? .gray : .black
 77      
 78      self.quantityLabel.text = String(describing: quantity)
 79      self.delegate?.updateCartItem(cell: self, quantity: quantity)
 80     }
 81   }
The segues are connected properly. So, I suspect rightBarButtonItem i.e. Checkout(2) to another CartViewcontroller.

I have been thinking over it for quite some time.

I would sincerely appreciate your assistance. It would mean a lot to me.
Posted
Updated 22-Sep-20 5:09am
v4

1 solution

It was a rookie mistake. I had named the Segue incorrectly. It is “showCart” in the ProductViewController, while I was naming it “ShowCart” i.e. upper case letter “S”. It is puny but formidable ! Anyways, thanks for looking into my problem.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS


CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900