Как связать табличное представление с несколькими разделами, которые представляют разные типы данных, используя RxSwift и RxSwiftDataSources?
Я пытаюсь создать табличное представление с несколькими разделами, используя RxSwift. Каждый раздел отображает данные, представляющие разные типы.
Я нашел RxSwiftDataSources
библиотека и реализованный пример из их документации.
Вот краткий обзор того, как реализован этот пример:
Пользовательский тип данныхCustomData
определено:
struct CustomData {
var anInt: Int
var aString: String
var aCGPoint: CGPoint
}
Затем добавляются представления для раздела (обратите внимание, чтоSectionModelType
здесь реализовано):
struct SectionOfCustomData {
var header: String
var items: [Item]
}
extension SectionOfCustomData: SectionModelType {
typealias Item = CustomData
init(original: SectionOfCustomData, items: [Item]) {
self = original
self.items = items
}
}
Наконец, некоторые образцы данных создаются и привязываются к табличному представлению:
let sections: [SectionOfCustomData] = [
SectionOfCustomData(header: "First section", items: [CustomData(anInt: 0, aString: "zero", aCGPoint: CGPoint.zero), CustomData(anInt: 1, aString: "one", aCGPoint: CGPoint(x: 1, y: 1)) ]),
SectionOfCustomData(header: "Second section", items: [CustomData(anInt: 2, aString: "two", aCGPoint: CGPoint(x: 2, y: 2)), CustomData(anInt: 3, aString: "three", aCGPoint: CGPoint(x: 3, y: 3)) ])
]
Теперь я хочу изменить пример и хочу отображать толькоString
с, а не случаиCustomData
во втором разделе, примерно так:
let sections = [
SectionOfCustomData(header: "First section", items: [CustomData(anInt: 0, aString: "zero", aCGPoint: CGPoint.zero), CustomData(anInt: 1, aString: "one", aCGPoint: CGPoint(x: 1, y: 1)) ]),
SectionOfString(header: "Second section", items: ["a", "b", "c"])
]
Это, очевидно, не скомпилируется какsections
теперь содержит элементы разных типовSectionOfCustomData
SectionOfString
, Я пытался обойти это, пытаясь объявить разделы как [SectionModelType]
но это не работает, компилятор жалуется:
ПротоколSectionModelType
'может использоваться только как общее ограничение, потому что оно имеет Self или требования к связанному типу
1 ответ
Вы можете использовать перечисления для упаковки различных типов.
Используя enum, определение SectionOfCustomData должно выглядеть следующим образом:
enum SectionOfCustomData: SectionModelType {
typealias Item = Row
case customDataSection(header: String, items: [Row])
case stringSection(header: String, items: [Row])
enum Row {
case customData(customData: CustomData) // wrapping CustomData to Row type
case string(string: String) // wrapping String to Row type
}
// followings are not directly related to this topic, but represents how to conform to SectionModelType
var items: [Row] {
switch self {
case .customDataSection(_, let items):
return items
case .stringSection(_, let items):
return items
}
}
public init(original: SectionOfCustomData, items: [Row]) {
switch self {
case .customDataSection(let header, _):
self = .customDataSection(header: header, items: items)
case .stringSection(let header, _):
self = .stringSection(header: header, items: items)
}
}
}
И configureCell выглядит так:
let dataSource = RxTableViewSectionedReloadDataSource<SectionOfCustomData>()
...
dataSource.configureCell = { [weak self] (dataSource, tableView, indexPath, row) -> UITableViewCell in
switch dataSource[indexPath] {
case .customData(let customData):
let cell: CustomDataCell = // dequeue cell
self?.configure(cell: cell, with: customData)
return cell
case .string(let string):
let cell: StringCell = // dequeue cell
self?.configure(cell: cell, with: string)
return cell
}
}