简体   繁体   中英

Swift different types of generics in array

So I'm creating some view models for UITableView. The table has different cell types, so I used generics, but there were some problems when putting them into arrays.

First I defined a struct:

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
}

then I declared an array:

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

The problems are:

  1. I can't specify the type of array because they are actually different generics.
  2. If I use [Any] as the type of the array, then every time I take an element, I have to convert it to the corresponding type, which is inconsistent with my original design.
  3. I did some searching and realized that I might need to use a protocol to solve the problem, but I tried many times and failed.

The result I expect is that when I take an element, I can get its type correctly without conversion.

My current approach is like:

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

It is obviously not elegant enough, I would like to ask if there is a better solution, any help or advice is very grateful.

You can use protocol for your row object, and use identifier instead of type, I'm not totally sure this will fix your problem completely but you can try it:

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

Let your custom cell class to conform to CellProtocol , then inside there bind function, try to convert the RowProtocol into Row1 or Row2 to get their values.

Also Im not sure how you are going to configure inside that sections object, it feels off, I rather let the cell class to handle configuration itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM