How to deal with dynamic Sections and Rows in iOS UITableView

前提是你 提交于 2020-04-26 23:24:10

问题


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.


回答1:


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



回答2:


It is a bad practice to use NSDictionary for storing data. Create new class for section (i.e. SectionData) and row (i.e. RowData). Your ViewController (or some other data provider) will keep array of SectionData, where SectionData keeps array of RowData. RowData may contain func for handling row selection, so in didSelectRowAtindexPath you just do something like this:

let rowData = rowDataAtIndexPath(indexPath)
rowData.tapHandler()

where rowDataAtIndexPath is your defined function that gives you data for indexPath.

When you need to remove some section, just remove it from array of sections and reload tableView.




回答3:


I think this talk is broader than what you are seeking but he talks about it.

https://realm.io/news/altconf-benji-encz-uikit-inside-out-declarative-programming/



来源:https://stackoverflow.com/questions/40128423/how-to-deal-with-dynamic-sections-and-rows-in-ios-uitableview

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