Skip to content

Instantly share code, notes, and snippets.

@asmallteapot
Last active March 7, 2019 01:55
Show Gist options
  • Save asmallteapot/07f365c56cebdb6835eb to your computer and use it in GitHub Desktop.
Save asmallteapot/07f365c56cebdb6835eb to your computer and use it in GitHub Desktop.
An attempt at making UITableView cell reuse a bit more idiomatic in Swift.
@objc class ExampleTableCell: UITableViewCell, ReuseableObject, NibLoadable {}
@objc class ExampleViewController: UITableViewController {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(style: UITableViewStyle) {
super.init(style: style)
self.tableView.registerCellType(ExampleTableCell)
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: ExampleTableCell = tableView.dequeueCellForIndexPath(indexPath)
// configure the cell ...
return cell
}
}
extension UITableView {
// I want to be able to write typealiases with constraints to simplify method signatures
typealias ReusableCell = UITableViewCell where ReusableObject
typealias NibLoadableCell = ReusableCell where NibLoadable
func registerCellType(cellType: ReusableCell.Type) {
self.registerClass(cellType, forCellReuseIdentifier: cellType.ReuseIdentifier)
}
func registerNibForCellType(cellType: NibLoadableCell.Type) {
self.registerNib(cellType.Nib, forCellReuseIdentifier: cellType.ReuseIdentifier)
}
}
protocol NibLoadable {
static var NibName: String { get }
static var NibBundle: NSBundle? { get }
}
extension NibLoadable {
static var Nib: UINib {
get {
return UINib(nibName: self.NibName, bundle: self.NibBundle)
}
}
}
extension NibLoadable {
static var NibName: String {
get {
return String(self)
}
}
static var NibBundle: NSBundle? {
get {
return nil
}
}
}
protocol ReusableObject {
static var ReuseIdentifier: String { get }
}
extension ReusableObject {
static var ReuseIdentifier: String {
get {
return String(self)
}
}
}
extension UITableView {
typealias Cell = UITableViewCell
func registerCellType<C: Cell where C: ReusableObject>(cellType: C.Type) {
self.registerClass(cellType, forCellReuseIdentifier: cellType.ReuseIdentifier)
}
func registerNibForCellType<C: Cell where C: ReusableObject, C: NibLoadable>(cellType: C.Type) {
self.registerNib(cellType.Nib, forCellReuseIdentifier: cellType.ReuseIdentifier)
}
func dequeueCellOfType<C: Cell where C: ReusableObject>(cellType: C.Type, forIndexPath indexPath: NSIndexPath) -> C? {
return self.dequeueReusableCellWithIdentifier(cellType.ReuseIdentifier, forIndexPath: indexPath) as? C
}
func dequeueCellForIndexPath<C: Cell where C: ReusableObject>(indexPath: NSIndexPath) -> C? {
return self.dequeueReusableCellWithIdentifier(C.ReuseIdentifier, forIndexPath: indexPath) as? C
}
}
extension UITableView {
// "Scrubber" == "Section Index" in UIKit/ObjC terms
struct ScrubberConfig {
let minimumDisplayRowCount: Int
let textColor: UIColor?
let backgroundColor: UIColor?
let scrubbingBackgroundColor: UIColor?
init(minimumRows: Int = 0, textColor: UIColor? = nil, backgroundColor: UIColor? = nil, scrubbingBackgroundColor: UIColor? = nil) {
self.minimumDisplayRowCount = minimumRows
self.textColor = textColor
self.backgroundColor = backgroundColor
self.scrubbingBackgroundColor = scrubbingBackgroundColor
}
}
var scrubberConfig: ScrubberConfig {
get {
return ScrubberConfig(minimumRows: self.sectionIndexMinimumDisplayRowCount, textColor: self.sectionIndexColor, backgroundColor: self.sectionIndexBackgroundColor, scrubbingBackgroundColor: self.sectionIndexTrackingBackgroundColor)
}
set(newValue) {
self.sectionIndexMinimumDisplayRowCount = newValue.minimumDisplayRowCount
self.sectionIndexColor = newValue.textColor
self.sectionIndexBackgroundColor = newValue.backgroundColor
self.sectionIndexTrackingBackgroundColor = newValue.scrubbingBackgroundColor
}
}
}
// not totally happy with this nickname for the concept
extension UITableView {
typealias SectionView = UITableViewHeaderFooterView
func registerSectionViewType<V: SectionView where V: ReusableObject>(viewType: V.Type) {
self.registerClass(viewType, forHeaderFooterViewReuseIdentifier: viewType.ReuseIdentifier)
}
func registerNibForSectionViewType<V: SectionView where V: ReusableObject, V: NibLoadable>(viewType: V.Type) {
self.registerNib(viewType.Nib, forHeaderFooterViewReuseIdentifier: viewType.ReuseIdentifier)
}
func dequeueSectionViewOfType<V: SectionView where V: ReusableObject>(viewType: V.Type) -> V? {
return self.dequeueReusableHeaderFooterViewWithIdentifier(viewType.ReuseIdentifier) as? V
}
}
extension UITableViewCell {
typealias SeparatorStyle = UITableViewCellSeparatorStyle
}
extension UITableView {
// TODO: rename "config" to something nicer
struct SeparatorConfig {
let style: Cell.SeparatorStyle
let color: UIColor?
let inset: UIEdgeInsets
let effect: UIVisualEffect?
static func Default() -> SeparatorConfig {
return self.init(style: .SingleLine, color: nil, inset: UIEdgeInsetsZero, effect: nil)
}
}
var separatorConfig: SeparatorConfig {
get {
// MARK: WARNING: force unwrap
return SeparatorConfig(style: self.separatorStyle, color: self.separatorColor, inset: self.separatorInset, effect: self.separatorEffect)
}
set(newValue) {
self.separatorStyle = newValue.style
self.separatorColor = newValue.color
self.separatorInset = newValue.inset
self.separatorEffect = newValue.effect
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment