如何处理 iOS UITableView 中的动态部分和行

How to deal with dynamic Sections and Rows in iOS UITableView

我的问题

当我处理 UITableView 时,我基本上有一个包含部分和行的数组 table_data

[
   {
      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}
      ]
   },
]

我使用 heightForHeaderInSectioncellForRowAtindexPathtitleForHeaderInSectiondidSelectRowAtindexPath 这样的方法

 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
 }

当我的 table_data 数组是动态的时,使用数字 01 等变得令人头疼。动态意味着某些部分或行可以有不同的位置或根本不存在。

比如我去掉A段,我的数组是

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

我喜欢这个

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 
}

添加另一个 C 部分作为 0 元素

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
}

然后在函数中使用section_positions

 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
 }

看起来很简单,但是当我有很多节和很多情况要隐藏或移动它在数组中时,控制和添加新类型的节就变得困难了。有时我创建 section_positions_map 数组将它们存储在一起并在循环中进行 +1, -1 操作。但这无济于事,当我需要这种行为时,仍然很难在每个 TableViewController 中组织它。

问题

你知道有什么方法或框架可以让这部分变得更容易吗?

我的想法

  1. type 属性 添加到我的词典
{
  title : "section A title",
  rows: [
      {data: row_1_data},
      {data: row_2_data}
  ]
  type : "section_a"
}

并检查 if table_data[0]["type"] == "section_a"(或使用 enum 来收集类型)

  1. 子类化我的词典并检查

if table_data[0] is SubClassSectionA

但我觉得他们两个都很丑。

使用 NSDictionary 存储数据是一种不好的做法。为部分(即 SectionData)和行(即 RowData)创建新的 class。您的 ViewController(或其他一些数据提供者)将保留 SectionData 数组,其中 SectionData 保留 RowData 数组。 RowData 可能包含用于处理行选择的函数,因此在 didSelectRowAtindexPath 中你只需执行如下操作:

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

其中 rowDataAtIndexPath 是您定义的函数,它为您提供 indexPath 的数据。

当您需要删除某些部分时,只需将其从部分数组中删除并重新加载 tableView。

我认为这个谈话比你正在寻找的更广泛,但他谈到了。

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

我在创建一个我知道所有可能部分的 table 时使用的方法是使用枚举。您为每个可能的部分类型创建一个枚举:

enum SectionTypes { case sectionA, sectionB, sectionC }

然后创建一个变量来保存这些部分:

var sections: [SectionTypes]

当您准备好数据后,您可以使用需要显示的部分填充部分。我通常也会做一个方法来帮助获取部分:

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

有了这个,您就可以开始实现通用的数据源委托方法了:

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