Created
October 15, 2016 20:12
-
-
Save AlexanderZ-aFrogleap/e77bc15148e182a1ffde5fb6b1dc8992 to your computer and use it in GitHub Desktop.
Generic UITableView adapter with sections
This file contains 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
//: Playground - noun: a place where people can play | |
import UIKit | |
protocol SectionModel { | |
var count: Int { get } | |
func cell(at: Int) -> UITableViewCell | |
func selected(at: Int) | |
} | |
class Adapter: NSObject { | |
let sections: [SectionModel] | |
init(sections: [SectionModel]) { | |
self.sections = sections | |
} | |
} | |
extension Adapter: UITableViewDelegate, UITableViewDataSource { | |
func numberOfSections(in tableView: UITableView) -> Int { | |
return sections.count | |
} | |
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { | |
return sections[section].count | |
} | |
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { | |
let section = sections[indexPath.section] | |
return section.cell(at: indexPath.row) | |
} | |
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | |
let section = sections[indexPath.section] | |
section.selected(at: indexPath.row) | |
} | |
} | |
protocol Adaptable { | |
associatedtype Model | |
func adapt(model: Model) | |
} | |
class GenericSectionModel<Model, Cell>: SectionModel where Cell: UITableViewCell, Cell: Adaptable, Cell.Model == Model { | |
typealias ModelCellClosure = (Model, Cell) -> () | |
private let items: [Model] | |
private lazy var cells: [Cell] = self.createCells() | |
var onSelected: ModelCellClosure? = nil | |
var count: Int { | |
return items.count | |
} | |
init(items: [Model]) { | |
self.items = items | |
} | |
func cell(at: Int) -> UITableViewCell { | |
return cells[at] | |
} | |
func createCells() -> [Cell] { | |
return items.map { m in | |
let c = Cell() | |
c.adapt(model: m) | |
return c | |
} | |
} | |
func selected(at: Int) { | |
let m = items[at] | |
let c = cells[at] | |
onSelected?(m, c) | |
} | |
} | |
extension UITableView { | |
func setAdapter(_ adapter: Adapter) { | |
dataSource = adapter | |
delegate = adapter | |
reloadData() | |
} | |
} | |
// Usage | |
struct User { | |
let name: String | |
} | |
class UserCell: UITableViewCell, Adaptable { | |
func adapt(model: User) { | |
textLabel?.text = model.name | |
} | |
} | |
struct Account { | |
let id: String | |
} | |
class AccountCell: UITableViewCell, Adaptable { | |
func adapt(model: Account) { | |
textLabel?.text = model.id | |
textLabel?.textColor = UIColor.red | |
} | |
} | |
let users = [User(name: "Test User 0"), | |
User(name: "Test User 1"), | |
User(name: "Test User 2"), | |
User(name: "Test User 3"), | |
User(name: "Test User 4"), | |
User(name: "Test User 5"), | |
User(name: "Test User 6")] | |
let accs = [Account(id: "test_acc")] | |
let usersSection = GenericSectionModel<User, UserCell>(items: users) | |
usersSection.onSelected = { m, c in | |
print(m) | |
print(c) | |
} | |
let accountsSection = GenericSectionModel<Account, AccountCell>(items: accs) | |
let adapter = Adapter(sections: [usersSection, accountsSection]) | |
let table = UITableView(frame: CGRect(x: 0, y: 0, width: 200, height: 400), style: .grouped) | |
table.setAdapter(adapter) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment