Search code examples
iosswiftxcodeuitableviewsections

How to deal with dynamic Sections and Rows in iOS UITableView


My issue

When I deal with UITableView, I basically have an Array table_data with my sections and rows.

[
   {
      title : "section A title",
      rows: [
          {data: row_1_data},
          {data: row_2_data}
      ]
   },
   {
      title : "section B title",
      rows: [
          {data: row_1_data},
          {data: row_2_data}
      ]
   },
]

I use heightForHeaderInSection, cellForRowAtindexPath, titleForHeaderInSection, didSelectRowAtindexPath methods like this

 if indexPath.section == 0 {
        //section A
        if indexPath.row == 0 {
             //do something with table_data[0]["rows"][0]["data"]
        }
        elesif indexPath.row == 1 {
             //do something else
        }
 }
 if indexPath.section == 1 {
      //do something for section B
 }

Working with numbers 0, 1, etc becomes a headache, when my table_data array is dynamic. Dynamic means, that some sections or rows can have different positions or don't exist at all.

For example, I remove A section and my array is

[
   {
      title : "section B title",
      rows: [
          {data: row_1_data},
          {data: row_2_data}
      ]
   }
]

I do like this

self.section_A_position = 0
self.section_B_position = 1
func afterRemoveSectionA() {
    section_A_position = -999
    section_B_position = section_B_position - 1
    //write here another new sections for -1 
}

Add another section C as 0 element

self.section_C_position = -999
func afterAddSectionC() {
   section_C_position = 0
   section_A_position = section_A_position + 1
   section_B_position = section_B_position + 1
}

And then use section_positions in functions

 if indexPath.section == section_A_position {
        //section A
        if indexPath.row == 0 {
             //do something with table_data[0]["rows"][0]["data"]
        }
        elesif indexPath.row == 1 {
             //do something else
        }
 }
 if indexPath.section == section_B_position {
      //do something for section B
 }

It looks pretty simple, but when I have many sections and many cases to hide or move it in array, it becomes difficult to control and add new types of sections. Sometimes I create section_positions_map array to store it together and make +1, -1 operation in loop. But it doesn't help it is still difficult to organize it in every TableViewController, when I need this behavior.

Question

Do you know any approaches or frameworks that make this part easier?

My Ideas

  1. Add type property to my Dictionaries
{
  title : "section A title",
  rows: [
      {data: row_1_data},
      {data: row_2_data}
  ]
  type : "section_a"
}

and check if table_data[0]["type"] == "section_a" (or use enum to collect types)

  1. Subclass my Dictionary and check

if table_data[0] is SubClassSectionA

but both of them looks ugly for me.


Solution

  • An approach I use when creating a table where I know all the possible sections is with enums. You create an enum for each of the possible section types:

    enum SectionTypes { case sectionA, sectionB, sectionC }

    And then create a variable to hold the sections:

    var sections: [SectionTypes]

    When you have your data ready then you populate sections with the sections that needs to be displayed. I usually also make a method to help get the section:

    func getSection(forSection: Int) -> SectionTypes {
            return sections[forSection]
        }
    

    With this in place you can start implementing the common DataSource delegate methods:

    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return sections.count
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        switch getSection(forSection: section) {
        case .sectionA:
            return 0 //Add the code to get the count of rows for this section
        case .sectionB:
            return 0
        default:
            return 0
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        switch getSection(forSection: indexPath.section) {
        case .sectionA:
            //Get section A cell type and format as your need
        //etc
        }
    }