swift how to divide tableview into sections with add to cart working properly?

狂风中的少年 提交于 2021-02-05 11:22:48

问题


This has got me in a crazy-spin. I’ve been ruminating over this for quite some time, have tried every trick of the trade, but with no luck..

I will be greatly indebted if you solve my problem.

My issue is that when I divide ProductViewController into sections:-

i)The cells i.e. images are not in correct order.

ii) Add to cart button does not function properly.

Note: - If the following code seems extensive to you, leave the rest of the code, just ook at the ProductViewController - I just want to be able to divide the ProductViewController to divide into sections as per my wish with Add to cart button working properly, most probably without changing the model. I have put the lengthy code just in case and also to show what I have tried (with the help of others).

If you are very short of time, I have also asked the incomprehensive or smaller version of the issue here - UITableView with Sections Repeating cell data in all the sections, but I would still request you to read my full code below -

I will elucidate both the points later. First see my code please -

Models -

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 productarray = [Product(name: "a", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "blue")),
               Product(name: "b", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "CakeImage")),Product(name: "c", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "vectorlogo")),
                Product(name: "d", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "PeasImge")),Product(name: "e", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "castle")),
                Product(name: "f", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "scoobydoo")),Product(name: "g", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "ufo")),
                Product(name: "h", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "wolfsky")),Product(name: "i", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "universe")),
                Product(name: "j", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "werewolf")),Product(name: "k", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "galaxy"))]

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
  }
}

class ProductViewController -

import UIKit
class ProductViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let sections = ["Section A", "Section B","Section C", "Section D","Section E"]
let rowspersection = [2,3,2,2,2]
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 sections.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return rowspersection[section]
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell   {
    let cell = tableView.dequeueReusableCell(withIdentifier: "ProductTableViewCell") as!   ProductTableViewCell
    cell.delegate = self 
    
    var index = indexPath.row
    if indexPath.section != 0, rowspersection.count > indexPath.section - 1{
        index += rowspersection[indexPath.section - 1]
    }
    
    if index < productarray.count {
        let data = productarray[index]
        cell.name?.text = data.name
        cell.imageView?.image =  data.imagename
        
        let product = productarray[index]
        cell.setButton(state: self.cart.contains(product: product))
      }
    return cell
  }
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 44
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
    switch(section) {
    case 0:return "Section A"
    case 1:return "Section B"
    case 2:return "Section C"
    case 3:return "Section D"
    case 4:return "Section E"
   default :return ""
        
    }
  }
}
 extension ProductViewController: CartDelegate {

// MARK: - CartDelegate
func updateCart(cell: ProductTableViewCell) {
    guard let indexPath = tableView.indexPath(for: cell) else { return }
    var index = indexPath.row
    if indexPath.section != 0, rowspersection.count > indexPath.section - 1{
        index += rowspersection[indexPath.section - 1]
    }
    
    if index < productarray.count{
        let product = productarray[index]
        
        //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 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)!
   }

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.productarray.name
       // cell.priceLabel.text = cartItem.product.displayPrice()
       // cell.quantityLabel.text = String(describing: cartItem.quantity)
      
     cell.quantity = cartItem.quantity
     }
 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
    }
  }

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)
    }
 }

The result is this. First see the image please, and then I will explain what's fallacious

1)Images/cells in Model “struct Product” are in order - blue, CakeImage,vectorlogo, PeasImge, castle, scoobydoo, ufo, wolfsky, universe, werewolf, galaxy

but the images in Simulator (see image above) are in erratic pattern -

section A:blue,CakeImage, vectorlogo

section B: vectorlogo, PeasImge, castle.

section C:PeasImge, castle.

section D:PeasImge, castle.

section E:PeasImge, castle.

  1. Just the images are not erratic, the Add button on the cells also act erratically - Clicking on Add button in lower sections sometimes increase and decreases the rightBarButtonItem i.e. Chekcout(4)

I had asked a similar version of the problem earlier where a user PGDev had suggested -

instead of making different arrays, to create a single array of custom type and use that as the dataSource of your tableView. Example:

struct Section {
let name: String
let products: [Product] 
 }

let sections = [
Section(name: "Section A", products: [Product(name: "a", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "blue")),
               Product(name: "b", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "CakeImage"))]),
 Section(name: "Section B", products: [Product(name: "c", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "vectorlogo")),
                Product(name: "d", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "PeasImge")),Product(name: "e", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "castle"))]),
 Section(name: "Section C", products: [Product(name: "f", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "scoobydoo")),Product(name: "g", quantity: 5, price: 5.0,imagename:#imageLiteral(resourceName: "ufo"))]),
 Section(name: "Section D", products: [Product(name: "h", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "wolfsky")),Product(name: "i", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "universe"))]),
 Section(name: "Section E”, products: [ Product(name: "j", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "werewolf")),Product(name: "k", quantity: 10, price: 10.0, imagename:#imageLiteral(resourceName: "galaxy"))]]) 
 ]

i.e to use sections array as the dataSource to avoid a lot of confusion.

I am ready to do that as well and maybe this method is better but then I will have to change many parts of the code. How to go about that?

I just want to achieve the following targets-

  1. Dividing the cells/images of ProdutViewcontroller into sections as I wish.

  2. Add data to rightBarButtonItem i.e. Checkout correctly which should subsequently be transferred to CartViewController.

.. Make no haste. Take your own time to straighten out the issues but its crucial for me to fix them as I need similar code for a production app . I’m in dilema. Please bail me out. I’ll be much obliged.

来源:https://stackoverflow.com/questions/64043529/swift-how-to-divide-tableview-into-sections-with-add-to-cart-working-properly

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!