Skip to content

Instantly share code, notes, and snippets.

@yingmu52
Created June 29, 2018 06:46
Show Gist options
  • Save yingmu52/b20f011c397912dc85d926353d716ba8 to your computer and use it in GitHub Desktop.
Save yingmu52/b20f011c397912dc85d926353d716ba8 to your computer and use it in GitHub Desktop.
ksr datasource
public protocol ValueCell: class {
associatedtype Value
static var defaultReusableId: String { get }
func configureWith(value: Value)
}
open class ValueCellDataSource: NSObject {
private var values: [[(value: Any, reusableId: String)]] = []
open func configureCell(collectionCell cell: UICollectionViewCell, withValue value: Any) {}
open func configureCell(tableCell cell: UITableViewCell, withValue value: Any) {}
open func registerClasses(collectionView: UICollectionView?) {}
open func registerClasses(tableView: UITableView?) {}
public final func clearValues() {
self.values = [[]]
}
public final func clearValues(section: Int) {
self.padValuesForSection(section)
self.values[section] = []
}
@discardableResult
public final func prependRow <Cell: ValueCell, Value: Any>
(value: Value, cellClass: Cell.Type, toSection section: Int) -> IndexPath
where Cell.Value == Value {
self.padValuesForSection(section)
self.values[section].insert((value, Cell.defaultReusableId), at: 0)
return IndexPath(row: 0, section: section)
}
@discardableResult
public final func appendRow <Cell: ValueCell, Value: Any>
(value: Value, cellClass: Cell.Type, toSection section: Int) -> IndexPath where Cell.Value == Value {
self.padValuesForSection(section)
self.values[section].append((value, Cell.defaultReusableId))
return IndexPath(row: self.values[section].count - 1, section: section)
}
public final func appendStaticRow(cellIdentifier: String, toSection section: Int) {
self.padValuesForSection(section)
self.values[section].append(((), cellIdentifier))
}
public final func set(cellIdentifiers: [String], inSection section: Int) {
self.padValuesForSection(section)
self.values[section] = cellIdentifiers.map { ((), $0) }
}
public final func appendSection <Cell: ValueCell, Value: Any> (values: [Value], cellClass: Cell.Type)
where Cell.Value == Value {
self.values.append(values.map { ($0, Cell.defaultReusableId) })
}
public final func set <Cell: ValueCell, Value: Any>
(values: [Value], cellClass: Cell.Type, inSection section: Int) where Cell.Value == Value {
self.padValuesForSection(section)
self.values[section] = values.map { ($0, Cell.defaultReusableId) }
}
public final func set <Cell: ValueCell, Value: Any>
(value: Value, cellClass: Cell.Type, inSection section: Int, row: Int)
where Cell.Value == Value {
self.values[section][row] = (value, Cell.defaultReusableId)
}
public final subscript(indexPath: IndexPath) -> Any {
return self.values[indexPath.section][indexPath.item].value
}
public final subscript(itemSection itemSection: (item: Int, section: Int)) -> Any {
return self.values[itemSection.section][itemSection.item].value
}
public final subscript(section section: Int) -> [Any] {
return self.values[section].map { $0.value }
}
public final func numberOfItems() -> Int {
return self.values.reduce(0) { accum, section in accum + section.count }
}
public final func itemIndexAt(_ indexPath: IndexPath) -> Int {
return self.values[0..<indexPath.section]
.reduce(indexPath.item) { accum, section in accum + section.count }
}
}
// MARK: UITableViewDataSource methods
extension ValueCellDataSource: UITableViewDataSource {
public final func numberOfSections(in tableView: UITableView) -> Int {
return self.values.count
}
public final func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.values[section].count
}
public final func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let (value, reusableId) = self.values[indexPath.section][indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: reusableId, for: indexPath)
self.configureCell(tableCell: cell, withValue: value)
return cell
}
final func reusableId(item: Int, section: Int) -> String? {
if !self.values.isEmpty && self.values.count >= section &&
!self.values[section].isEmpty && self.values[section].count >= item {
return self.values[section][item].reusableId
}
return nil
}
final subscript(testItemSection itemSection: (item: Int, section: Int)) -> Any? {
let (item, section) = itemSection
if !self.values.isEmpty && self.values.count >= section &&
!self.values[section].isEmpty && self.values[section].count >= item {
return self.values[itemSection.section][itemSection.item].value
}
return nil
}
private func padValuesForSection(_ section: Int) {
guard self.values.count <= section else { return }
(self.values.count...section).forEach { _ in
self.values.append([])
}
}
}
// MARK: UICollectionViewDataSource methods
extension ValueCellDataSource: UICollectionViewDataSource {
public final func numberOfSections(in collectionView: UICollectionView) -> Int {
return self.values.count
}
public final
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.values[section].count
}
public final func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let (value, reusableId) = self.values[indexPath.section][indexPath.item]
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reusableId, for: indexPath)
self.configureCell(collectionCell: cell, withValue: value)
return cell
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment