Search code examples
iosarraysswifttableviewsections

How do you do you group sections in tableview?


What I’m trying to do is group the sections in the TableView. By sorting them by the storeName so that I can separate the items to go to its proper section and arranged by StoreName.

Im trying to present a couple of different sections of items in the list for each store. By grouping the sections based on StoreName.

The Items Array contains all the items for each in each section and shows which store the item belongs to.

How would I be able to group the sections for specific stores?

I know that im close at grouping my sections but im just not sure how to make it work correctly as well as it connecting to my Custom HeaderCell. I have a function written in my StoreVC called attemptToAssembleStoreGroups()

I just want to know how would I be able to group my items together by their storeName to have their own section for each store with its own list of items.

struct ItemSelection {
    let store: String
    let productName: String
    let productImage: UIImage
    let quantity: String
    let total: String
}

struct ItemSection {
    let title : String
    let stores : [ItemSelection]
}

class StoreVC: UITableViewController {

      fileprivate let cellId = "id123"

        let items = [
          ItemSelection(store: "Walmart",
               productName: "Bionicle",
               productImage: #imageLiteral(resourceName: "Bionicle"),
               quantity: "4",
               total: "24"),
          ItemSelection(store: "Walmart",
               productName: "PokeBall",
               productImage: #imageLiteral(resourceName: "PokeBall"),
               quantity: "2",
               total: "30"),
          ItemSelection(store: "Target",
               productName: "Beer",
               productImage: #imageLiteral(resourceName: "Beer"),
               quantity: "2",
               total: "30"),
          ItemSelection(store: "Lego Store",
               productName: "Star Wars Set",
               productImage: #imageLiteral(resourceName: "Star_Wars_Set"),
               quantity: "4",
               total: "256"),
          ItemSelection(store: "Lego Store",
               productName: "Indiana Jones Set",
               productImage: #imageLiteral(resourceName: "Indiana_Jones_Set"),
               quantity: "2",
               total: "88"),
          ItemSelection(store: "Amazon",
               productName: "Coconut Milk",
               productImage: #imageLiteral(resourceName: "Coconut_Milk"),
               quantity: "4",
               total: "20"),
          ItemSelection(store: "Amazon",
               productName: "32 inch Tv",
               productImage: #imageLiteral(resourceName: "TV"),
               quantity: "1",
               total: "156"),
          ItemSelection(store: "Amazon",
               productName: "Amazon Echo",
               productImage: #imageLiteral(resourceName: "Amazon_Echo"),
               quantity: "1",
               total: "80"),
          ItemSelection(store: "Amazon",
               productName: "Grill",
               productImage: #imageLiteral(resourceName: "Grill"),
               quantity: "3",
               total: "90"),
          ItemSelection(store: "Amazon",
               productName: "Coconut Bar",
               productImage: #imageLiteral(resourceName: "coconuts"),
               quantity: "4",
               total: "240")
         ]

      var itemSelection = [[ItemSelection]]()
      var storeArray = [String]()
      var itemSections = [ItemSection]()

     override func viewDidLoad() {
        super.viewDidLoad()

        for index in self.items {
            storeArray.append(index.store)
        }

        let groupedDictionary = Dictionary(grouping: items, by: {String($0.store.prefix(1))})
        let keys = groupedDictionary.keys.sorted()
        itemSections = keys.map{ItemSection(title: $0, stores: groupedDictionary[$0]!.sorted(by: {$0.store < $1.store}))}
     }



     override func numberOfSections(in tableView: UITableView) -> Int {
         return itemSections.count
     }

     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
         return itemSections[section].stores.count
     }

     override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) as! StoreCell
         let itemSelections = itemSelection[indexPath.section][indexPath.row]
         cell.itemSelction = itemSelections
         return cell
     }

     override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
         let cartHeader = tableView.dequeueReusableCell(withIdentifier: "Header") as! HeaderCell

         let stores = itemSelection[section]

         cartHeader.storeName.text = "Store: \(stores)"

         return cartHeader
     }

     override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
         return 45
     }

}

class StoreCell: UITableViewCell {

    @IBOutlet weak var itemQty: UILabel!
    @IBOutlet weak var itemName: UILabel!
    @IBOutlet weak var itemPrice: UILabel!
    @IBOutlet weak var itemImage: UIImage!

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

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

        // Configure the view for the selected state
    }

    var itemSelection: ItemSelection! {
        didSet {
            itemName.text = itemSelection.productName
            itemQty.text = "Qty: \(itemSelection.quantity)"
            itemPrice.text = "$\(itemSelection.total)"
            itemImage.image = itemSelection.productImage
        }

    }

}

class HeaderCell: UITableViewCell {

    @IBOutlet weak var storeName: UILabel!

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

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

        // Configure the view for the selected state
    }

}

Solution

  • found my solution

    import Foundation
    
    struct Items {
        let store: String
        let productName: String
        let productImage: UIImage
        let quantity: String
        let price: String
    }
    
    extension Items: Comparable {
        static func < (lhs: Items, rhs: Items) -> Bool {
            if lhs.store < rhs.store { return true }
            else { return lhs.store == rhs.store && lhs.productName < rhs.productName }
        }
    }
    
    extension Items {
        static let retail: [Items] = [
            .init(store: "Amazon",
                  productName: "Care Bear",
                  productImage: #imageLiteral(resourceName: "Bear"),
                  quantity: "4",
                  price: "156"),
            .init(....
        ]
    }
    

    import Foundation
    
    class ItemDataSource: NSObject {
        var sections: [String: [Items]] = [:]
    
        var items: [String] {
            return sections.keys.sorted()
        }
    
        var indexes: [String] {
            return items
                .map { String($0.first!) }
                .reduce(into: Set<String>(), { $0.insert($1) })
                .sorted()
        }
    
        init(stores: [Items]) {
            for store in retail.sorted(by: <) {
                let items = store.items
                if var stores = sections[items] {
                    stores.append(store)
                    sections[items] = stores
                } else {
                    sections[items] = [store]
                }
            }
        }
    }
    

    class StoreHeader: UITableViewCell {
    
        @IBOutlet weak var dispensaryName: UILabel!
    
        var store: String? {
            didSet { storeName.text = "Store: \(store!)" }
        }
    
    }
    

    class StoreCell: UITableViewCell {
    
        @IBOutlet weak var productImage: UIImageView!
        @IBOutlet weak var productQty: UILabel!
        @IBOutlet weak var productPrice: UILabel!
        @IBOutlet weak var productName: UILabel!
    
        var product: String? {
            didSet { productName.text = product }
        }
        var quantity: String? {
            didSet { productQty.text = "Qty: \(quantity!)" }
        }
        var price: String? {
            didSet { productPrice.text = "$\(price!)" }
        }
        var img: UIImage? {
            didSet { productImage.image = img }
        }
    
    }
    

    import UIKit
    
    class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        let dataSource: ItemDataSource = .init(stores: Items.stores)
    
        @IBOutlet weak var tableView: UITableView!
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return dataSource.sections.count
        }
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            let store = dataSource.items[section]
            return dataSource.sections[store]?.count ?? 0
        }
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
             let storeCell = tableView.dequeueReusableCell(withIdentifier: "StoreCell") as! StoreCell
            let store = dataSource.items[indexPath.section]
            let storeItem = dataSource.sections[store]?[indexPath.row]
    
            storeCell.product = storeItem?.productName
            storeCell.price = storeItem?.price
            storeCell.quantity = storeItem?.quantity
            storeCell.img = storeItem?.productImage
    
            return storeCell
        }
        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            let storeHeader = tableView.dequeueReusableCell(withIdentifier: "StoreHeader") as! StoreHeader
            storeHeader.store = dataSource.items[section]
            return storeHeader
        }
        func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
            return 45
        }