Last active
April 18, 2018 17:33
-
-
Save pejalo/678e32054b889f70e5fd968955a3b52c to your computer and use it in GitHub Desktop.
Attempt to define UITableViews more declaratively
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// TableViewDataSource.swift | |
// | |
import UIKit | |
////////////////////////////// | |
// Project code | |
////////////////////////////// | |
// MARK: - | |
/** | |
This is how I want to define UITableViews. Each section only needs one type of reusable cell. | |
This table view has two sections: One for string-based views, and one for color-based views. | |
*/ | |
class MyStringAndColorTableView: UITableView { | |
let stringValues = ["First", "Second"] | |
let colorValues: [UIColor] = [.blue, .brown] | |
init() { | |
super.init(frame: .zero, style: .plain) | |
let stringSection = TableViewSection(values: stringValues, reuseIdentifier: UILabel.reuseIdentifier) { (string, view) -> UIView in | |
let label = view as? UILabel ?? UILabel() | |
label.text = string | |
return label | |
} | |
let colorSection = TableViewSection(values: colorValues, reuseIdentifier: UIView.reuseIdentifier) { (color, view) -> UIView in | |
let view = view ?? UIView() | |
view.backgroundColor = color | |
return view | |
} | |
// Current error in Xcode: Heterogeneous collection literal could only be interred to '[Any]'; add explicit type annotation if this is intentional | |
let sections = [stringSection, colorSection] | |
// Current error in Xcode: Cannot convert value of type '[Any]' to expected argument type '[TableViewSection<Any>]' | |
let dataSource = TableViewDataSource(sections: sections) | |
self.dataSource = dataSource | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
} | |
////////////////////////////// | |
// Library code | |
////////////////////////////// | |
// MARK: - | |
struct TableViewSection<GenericValue> { | |
let values: [GenericValue] | |
let reuseIdentifier: String | |
let viewAt: (_ value: GenericValue, _ view: UIView?) -> UIView | |
} | |
// MARK: - | |
class TableViewDataSource: NSObject, UITableViewDataSource { | |
// The crux of the problem: How to define an array whose content's types contain multiple different generics? | |
var sections = [TableViewSection<Any>]() | |
init(sections: [TableViewSection<Any>]) { | |
self.sections = sections | |
} | |
// UITableViewDataSource | |
func numberOfSections(in tableView: UITableView) -> Int { | |
return sections.count | |
} | |
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
let tableViewSection = sections[section] | |
return tableViewSection.values.count | |
} | |
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let tableViewSection = sections[indexPath.section] | |
let dequeuedCell = tableView.dequeueReusableCell(withIdentifier: tableViewSection.reuseIdentifier) | |
let dequeuedView = (dequeuedCell as? TableViewCell)?.view ?? dequeuedCell | |
let value = tableViewSection.values[indexPath.row] | |
let view = tableViewSection.viewAt(value, dequeuedView) | |
return view as? UITableViewCell ?? TableViewCell(view: view) | |
} | |
} | |
// MARK: - | |
/** | |
This convenience UITableViewCell subclass allows you to create cells from simple UIViews. | |
*/ | |
class TableViewCell: UITableViewCell { | |
var view: UIView | |
init(view: UIView) { | |
self.view = view | |
super.init(style: .default, reuseIdentifier: type(of: view).reuseIdentifier) | |
contentView.addSubview(view) | |
// Pin edges of view to contentView via autolayout... | |
} | |
required init?(coder aDecoder: NSCoder) { | |
fatalError("init(coder:) has not been implemented") | |
} | |
} | |
// MARK: - | |
extension UIView { | |
static var reuseIdentifier: String { return String(describing: self) } | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment