Skip to content

Instantly share code, notes, and snippets.

@Koshimizu-Takehito
Last active March 9, 2021 20:29
Show Gist options
  • Save Koshimizu-Takehito/717a40a309c635a47fb677c738f8ba4e to your computer and use it in GitHub Desktop.
Save Koshimizu-Takehito/717a40a309c635a47fb677c738f8ba4e to your computer and use it in GitHub Desktop.
DataSource, CellProvider をビューコントローラから委譲するサンプルコード
import UIKit
extension UITableView {
func register(_ type: UITableViewCell.Type, identifier: String? = nil) {
self.register(type, forCellReuseIdentifier: identifier ?? String(describing: type))
}
func register(@ArrayBuilder<UITableViewCell.Type> builder: () -> [UITableViewCell.Type]) {
builder().forEach { type in
register(type)
}
}
func dequeue<Cell: UITableViewCell>(_ type: Cell.Type = Cell.self, identifier: String? = nil, for indexPath: IndexPath) -> Cell {
self.dequeueReusableCell(withIdentifier: identifier ?? String(describing: type), for: indexPath) as! Cell
}
}
@_functionBuilder
struct ArrayBuilder<T> {
static func buildBlock(_ items: T...) -> [T] {
items
}
}
class ArrayDataSource<Item>: NSObject, UITableViewDataSource {
typealias CellProvider = (UITableView, IndexPath, Item) -> UITableViewCell?
private let cellProvider: CellProvider
private var items: [[Item]] = []
private unowned let tableView: UITableView
init(tableView: UITableView, cellProvider: @escaping CellProvider) {
self.cellProvider = cellProvider
self.tableView = tableView
super.init()
tableView.dataSource = self
}
func apply(multiSectionItems items: [[Item]]) {
self.items = items
self.tableView.reloadData()
}
func apply(items: [Item] = []) {
self.apply(multiSectionItems: [items])
}
func apply(@ArrayBuilder<Item> builder: () -> [Item]) {
self.apply(items: builder())
}
func numberOfSections(in tableView: UITableView) -> Int {
items.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
items[section].count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
cellProvider(tableView, indexPath, items[indexPath.section][indexPath.row])!
}
}
enum Item {
case foo(FooItem)
case bar(BarItem)
case baz(BazItem)
}
struct FooItem {
}
struct BarItem {
}
struct BazItem {
}
class FooTableViewCell: UITableViewCell {
class func configure(cell: FooTableViewCell, with item: FooItem) -> FooTableViewCell {
return cell
}
}
class BarTableViewCell: UITableViewCell {
class func configure(cell: BarTableViewCell, with item: BarItem) -> BarTableViewCell {
return cell
}
}
class BazTableViewCell: UITableViewCell {
class func configure(cell: BazTableViewCell, with item: BazItem) -> BazTableViewCell {
return cell
}
}
class ViewController: UIViewController {
@IBOutlet private weak var tableView: UITableView!
private lazy var dataSource = ArrayDataSource(
tableView: tableView,
cellProvider: Provider.provide
)
override func viewDidLoad() {
super.viewDidLoad()
tableView.register {
FooTableViewCell.self
BarTableViewCell.self
BazTableViewCell.self
}
dataSource.apply {
Item.foo(FooItem())
Item.foo(FooItem())
Item.bar(BarItem())
Item.bar(BarItem())
Item.bar(BarItem())
Item.baz(BazItem())
Item.baz(BazItem())
Item.baz(BazItem())
Item.baz(BazItem())
}
}
}
private struct Provider {
static func provide(tableView: UITableView, indexPath: IndexPath, item: Item) -> UITableViewCell {
switch item {
case let .foo(item):
return FooTableViewCell.configure(
cell: tableView.dequeue(for: indexPath),
with: item
)
case let .bar(item):
return BarTableViewCell.configure(
cell: tableView.dequeue(for: indexPath),
with: item
)
case let .baz(item):
return BazTableViewCell.configure(
cell: tableView.dequeue(for: indexPath),
with: item
)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment