Mike
Mike

Reputation: 1331

How can I populate multiple tableview sections when the contents of the arrays are of different types?

I'm having a bit of a polymorphism issue. I've got three arrays aList, bList and cList that contain different types of equipment "A", "B", "C".

I want to populate a tableviewcontroller with 3 sections for aList, bList, cList. But i'm struggling a bit when I get to:

 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

The problem i'm having is that ideally i'd have three arrays within one array eg. section = [aList, bList, cList).

In my singleton "A", "B", "C" are structs and represent a type of equipment and so I changed them into classes and subclassed them from a "Equipment" superclass and then tried to create an array of the superclass "Equipment" but that didn't work either.

Advice would be great.

class EquipmentListController: UITableViewController {

    var model = SingletonModel.sharedInstance

    var aList:[SingletonModel.A] = []
    var bList:[SingletonModel.B]  = []
    var cList:[SingletonModel.C] = []

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func viewWillAppear(_ animated: Bool) {

        super.viewWillAppear(animated)
        aList = model.AList
        bList = model.BList
        cList = model.CList
        sections.append(aList)
        sections.append(bList)
        sections.append(cList)

    }

    override func numberOfSections(in tableView: UITableView) -> Int {

        return 3
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        switch section{
        case 1:
            self.tableView.rowHeight = 70
            return aList.count
        case 2:
            return bList.count
        case 3:
            return cList.count

        default:
            return 0
        }

    }

My problem is below with the line let equipment: SingletonModel.A (or B or C) - basically i've got three separate arrays and each is a different type.

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
    {

        guard let cell = tableView.dequeueReusableCell(withIdentifier: "equipmentcell", for: indexPath) as? EquipmentCell  else
        {

        }

        let equipment: SingletonModel.A (or B or C) = changeDataSource(indexPath: indexPath as NSIndexPath)

        cell.equipmentTitle.text = equipment.equipmentName       
        cell.accessoryType = .disclosureIndicator     
        return cell
    }

    func changeDataSource(indexPath: NSIndexPath) -> SingletonModel.A, B or C
    {
        var equipment:SingletonModel.A (B or C)
        equipment = A, B or C [indexPath.row]
        return equipment
    }

    func tableView(tableView: UITableView!, titleForHeaderInSection section: Int) -> String!
    {
        switch section
        {
        case 1:
            return "A"
        case 2:
            return "B"
        case 3:
            return "C"
        default:
            return nil
        }
    }

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

}

Thanks

Upvotes: 2

Views: 71

Answers (3)

mica
mica

Reputation: 4308

For each (equipment) type you can create your own cell type.

In

tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)

Switch on indexPath.section, create the matching cell type and set its attributes from the matching (equipment) array.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 727047

First you need to fix section numbering: sections are numbered from zero, not from one:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    switch section {
    case 0:
        return aList.count
    case 1:
        return bList.count
    case 2:
        return cList.count
    default:
        return -1 // Fail fast
    }
}

Next, change the way you set row height:

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    // Rows in section 0 are taller
    return indexPath.section == 0 ? 70.0 : 50.0;
}

Now you can set your cell up using A, B, or C:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    guard let cell = tableView.dequeueReusableCell(withIdentifier: "equipmentcell", for: indexPath) as? EquipmentCell  else
    {
        return nil
    }
    var equipment : BaseOfABC = nil
    switch indexPath.section {
    case 0:
        equipment = SingletonModel.A
    case 1:
        equipment = SingletonModel.B
    case 2:
        equipment = SingletonModel.C
    default:
        assert(indexPath.section < 3, "Unknown section")
    }
    cell.equipmentTitle.text = equipment.equipmentName       
    cell.accessoryType = .disclosureIndicator     
    return cell
}

Upvotes: 2

Maxime Tournier
Maxime Tournier

Reputation: 41

In indexPath you have the row and the section of the cell :

indexPath.row
indexPath.section

You can switch on indexPath.section

Upvotes: 2

Related Questions