How to deal with dynamic Sections and Rows in iOS UITableView
ios, sections, swift, uitableview, xcode
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
}
}
Problem
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 - 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) - Subclass my Dictionary and check `if table_data[0] is SubClassSectionA` but both of them looks ugly for me.