在数组中快速移动不同类型的泛型

时间:2018-07-18 02:36:19

标签: ios arrays swift generics

因此,我正在为UITableView创建一些视图模型。该表具有不同的单元格类型,因此我使用了泛型,但是将它们放入数组时存在一些问题。

首先,我定义了一个结构:

private struct Section<E, C> where C: UITableViewCell {
    let cell: C.Type
    let rows: [E]
    let configure: (_ row: E, _ cell: inout C, _ index: Int) -> Void
}

然后我声明了一个数组:

private lazy var sections: [Any] = [
    Section(cell: TextFieldTableViewCell.self,
            rows: [
              TableRow(image: R.image.home.device.settings.name(),
                       title: R.string.localizable.deviceSettingsViewControllerElementDeviceName(),
                       content: device.name,
                       action: { _ in

              }),
              TableRow(image: R.image.home.device.settings.location(),
                       title: R.string.localizable.deviceSettingsViewControllerElementDeviceLocation(),
                       content: device.location,
                       action: { _ in

              })],
            configure: { row, cell, index in
    }),
    Section(cell: DeviceSettingsNightVisionTableViewCell.self,
            rows: [
              TableRow(image: R.image.home.device.settings.nightVision(),
                       title: R.string.localizable.deviceSettingsViewControllerElementNightVision(),
                       content: 0,
                       action: { _ in
              })],
            configure: { row, cell, index in
    })
  ]

问题是:

  1. 我无法指定数组的类型,因为它们实际上是不同的泛型。
  2. 如果我使用[Any]作为数组的类型,那么每次获取元素时,都必须将其转换为对应的类型,这与我的原始设计不一致。
  3. 我做了一些搜索,发现我可能需要使用协议来解决问题,但是我尝试了很多次却失败了。

我期望的结果是,当我使用一个元素时,无需转换即可正确获取其类型。

我目前的做法是:

numberOfRowsInSection:中,

switch section {
        case 0:
          return (self.sections[section] as! Section<TableRow, TextFieldTableViewCell>).rows.count
        case 1:
          return (self.sections[section] as! Section<TableRow, DeviceSettingsNightVisionTableViewCell>).rows.count
        default:
          return 0
        }

显然还不够优雅,我想问一下是否有更好的解决方案,任何帮助或建议都将不胜感激。

1 个答案:

答案 0 :(得分:0)

您可以为行对象使用协议,并使用标识符代替类型,我不确定这是否可以完全解决您的问题,但是您可以尝试:

protocol CellProtocol where Self: UITableViewCell {
    func bind(_ object: RowProtocol)
}

protocol RowProtocol {

}

struct Row1: RowProtocol {

}

struct Row2: RowProtocol {

}

private struct Section {
    let cellIdentifier: String
    let rows: [RowProtocol]
    let configure: (_ row: RowProtocol, _ cell: inout UITableViewCell, _ index: Int) -> Void


}

private lazy var sections: [Section] = [
    Section(cellIdentifier: "cell1",
            rows: [Row1()],
            configure: { row, cell, index in
    }),
    Section(cellIdentifier: "cell2",
            rows: [Row2()],
            configure: { row, cell, index in
    })
]

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if let cell = tableView.dequeueReusableCell(withIdentifier: sections[indexPath.section].cellIdentifier, for: indexPath) as? CellProtocol {
        cell.bind(sections[indexPath.section].rows[indexPath.row])
    }
}

让您的自定义单元格类符合CellProtocol,然后在其中的bind函数中,尝试将RowProtocol转换为Row1Row2以获得他们的价值观。

我也不确定您将如何在这些sections对象中进行配置,感觉不对,我宁愿让单元类自行处理配置。