├── TableViewsWithMultipleCells.playground
├── Pages
│ └── Initial.xcplaygroundpage
│ │ ├── timeline.xctimeline
│ │ └── Contents.swift
├── playground.xcworkspace
│ └── contents.xcworkspacedata
└── contents.xcplayground
└── README.md
/TableViewsWithMultipleCells.playground/Pages/Initial.xcplaygroundpage/timeline.xctimeline:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/TableViewsWithMultipleCells.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Swift Talk
2 | ## Generic Table View Controllers (Part 2)
3 |
4 | This is the code that accompanies Swift Talk Episode 26: [Generic Table View Controllers (Part 2)](https://talk.objc.io/episodes/S01E26-generic-table-view-controllers-part-2)
5 |
--------------------------------------------------------------------------------
/TableViewsWithMultipleCells.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TableViewsWithMultipleCells.playground/Pages/Initial.xcplaygroundpage/Contents.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import PlaygroundSupport
3 |
4 |
5 | struct Album {
6 | var title: String
7 | }
8 |
9 | struct Artist {
10 | var name: String
11 | }
12 |
13 |
14 | struct CellDescriptor {
15 | let cellClass: UITableViewCell.Type
16 | let reuseIdentifier: String
17 | let configure: (UITableViewCell) -> ()
18 |
19 | init(reuseIdentifier: String, configure: @escaping (Cell) -> ()) {
20 | self.cellClass = Cell.self
21 | self.reuseIdentifier = reuseIdentifier
22 | self.configure = { cell in
23 | configure(cell as! Cell)
24 | }
25 | }
26 | }
27 |
28 | final class ItemsViewController- : UITableViewController {
29 | var items: [Item] = []
30 | let cellDescriptor: (Item) -> CellDescriptor
31 | var didSelect: (Item) -> () = { _ in }
32 | var reuseIdentifiers: Set = []
33 |
34 | init(items: [Item], cellDescriptor: @escaping (Item) -> CellDescriptor) {
35 | self.cellDescriptor = cellDescriptor
36 | super.init(style: .plain)
37 | self.items = items
38 | }
39 |
40 | required init?(coder aDecoder: NSCoder) {
41 | fatalError("init(coder:) has not been implemented")
42 | }
43 |
44 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
45 | let item = items[indexPath.row]
46 | didSelect(item)
47 | }
48 |
49 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
50 | return items.count
51 | }
52 |
53 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
54 | let item = items[indexPath.row]
55 | let descriptor = cellDescriptor(item)
56 |
57 | if !reuseIdentifiers.contains(descriptor.reuseIdentifier) {
58 | tableView.register(descriptor.cellClass, forCellReuseIdentifier: descriptor.reuseIdentifier)
59 | reuseIdentifiers.insert(descriptor.reuseIdentifier)
60 | }
61 |
62 | let cell = tableView.dequeueReusableCell(withIdentifier: descriptor.reuseIdentifier, for: indexPath)
63 | descriptor.configure(cell)
64 | return cell
65 | }
66 | }
67 |
68 |
69 | final class ArtistCell: UITableViewCell {
70 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
71 | super.init(style: .value1, reuseIdentifier: reuseIdentifier)
72 | }
73 |
74 | required init?(coder aDecoder: NSCoder) {
75 | fatalError("init(coder:) has not been implemented")
76 | }
77 | }
78 |
79 | final class AlbumCell: UITableViewCell {
80 | override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
81 | super.init(style: .value2, reuseIdentifier: reuseIdentifier)
82 | }
83 |
84 | required init?(coder aDecoder: NSCoder) {
85 | fatalError("init(coder:) has not been implemented")
86 | }
87 | }
88 |
89 |
90 | let artists: [Artist] = [
91 | Artist(name: "Prince"),
92 | Artist(name: "Glen Hansard"),
93 | Artist(name: "I Am Oak")
94 | ]
95 |
96 | let albums: [Album] = [
97 | Album(title: "Blue Lines"),
98 | Album(title: "Oasem"),
99 | Album(title: "Bon Iver")
100 | ]
101 |
102 | enum RecentItem {
103 | case artist(Artist)
104 | case album(Album)
105 | }
106 |
107 | let recentItems: [RecentItem] = [
108 | .artist(artists[0]),
109 | .artist(artists[1]),
110 | .album(albums[1])
111 | ]
112 |
113 | extension Artist {
114 | func configureCell(_ cell: ArtistCell) {
115 | cell.textLabel?.text = name
116 | }
117 | }
118 |
119 | extension Album {
120 | func configureCell(_ cell: AlbumCell) {
121 | cell.textLabel?.text = title
122 | }
123 | }
124 |
125 | extension RecentItem {
126 | var cellDescriptor: CellDescriptor {
127 | switch self {
128 | case .artist(let artist):
129 | return CellDescriptor(reuseIdentifier: "artist", configure: artist.configureCell)
130 | case .album(let album):
131 | return CellDescriptor(reuseIdentifier: "album", configure: album.configureCell)
132 | }
133 | }
134 | }
135 |
136 | let recentItemsVC = ItemsViewController(items: recentItems, cellDescriptor: { $0.cellDescriptor })
137 |
138 | let nc = UINavigationController(rootViewController: recentItemsVC)
139 |
140 | nc.view.frame = CGRect(x: 0, y: 0, width: 200, height: 300)
141 | PlaygroundPage.current.liveView = nc.view
142 |
143 |
144 |
--------------------------------------------------------------------------------