-
Notifications
You must be signed in to change notification settings - Fork 68
/
Copy pathTableViewDiffableDataSource.swift
208 lines (185 loc) · 7.98 KB
/
TableViewDiffableDataSource.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
#if os(iOS) || os(tvOS)
import UIKit
import DifferenceKit
/// A class for backporting `UITableViewDiffableDataSource` introduced in iOS 13.0+, tvOS 13.0+.
/// Represents the data model object for `UITableView` that can be applies the
/// changes with automatic diffing.
open class TableViewDiffableDataSource<SectionIdentifierType: Hashable, ItemIdentifierType: Hashable>: NSObject, UITableViewDataSource {
/// The type of closure providing the cell.
public typealias CellProvider = (UITableView, IndexPath, ItemIdentifierType) -> UITableViewCell?
/// The default animation to updating the views.
public var defaultRowAnimation: UITableView.RowAnimation = .automatic
private weak var tableView: UITableView?
private let cellProvider: CellProvider
private let core = DiffableDataSourceCore<SectionIdentifierType, ItemIdentifierType>()
/// Creates a new data source.
///
/// - Parameters:
/// - tableView: A table view instance to be managed.
/// - cellProvider: A closure to dequeue the cell for rows.
public init(tableView: UITableView, cellProvider: @escaping CellProvider) {
self.tableView = tableView
self.cellProvider = cellProvider
super.init()
tableView.dataSource = self
}
/// Applies given snapshot to perform automatic diffing update.
///
/// - Parameters:
/// - snapshot: A snapshot object to be applied to data model.
/// - animatingDifferences: A Boolean value indicating whether to update with
/// diffing animation.
/// - completion: An optional completion block which is called when the complete
/// performing updates.
public func apply(_ snapshot: DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType>, animatingDifferences: Bool = true, completion: (() -> Void)? = nil) {
core.apply(
snapshot,
view: tableView,
animatingDifferences: animatingDifferences,
performUpdates: { tableView, changeset, setSections in
tableView.reload(using: changeset, with: self.defaultRowAnimation, setData: setSections)
},
completion: completion
)
}
/// Returns a new snapshot object of current state.
///
/// - Returns: A new snapshot object of current state.
public func snapshot() -> DiffableDataSourceSnapshot<SectionIdentifierType, ItemIdentifierType> {
return core.snapshot()
}
/// Returns an item identifier for given index path.
///
/// - Parameters:
/// - indexPath: An index path for the item identifier.
///
/// - Returns: An item identifier for given index path.
public func itemIdentifier(for indexPath: IndexPath) -> ItemIdentifierType? {
return core.itemIdentifier(for: indexPath)
}
/// Returns an index path for given item identifier.
///
/// - Parameters:
/// - itemIdentifier: An identifier of item.
///
/// - Returns: An index path for given item identifier.
public func indexPath(for itemIdentifier: ItemIdentifierType) -> IndexPath? {
return core.indexPath(for: itemIdentifier)
}
/// Returns the number of sections in the data source.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
///
/// - Returns: The number of sections in the data source.
public func numberOfSections(in tableView: UITableView) -> Int {
return core.numberOfSections()
}
/// Returns the number of items in the specified section.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - section: An index of section.
///
/// - Returns: The number of items in the specified section.
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return core.numberOfItems(inSection: section)
}
/// Returns the title for the specified section's header.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - section: An index of section.
///
/// - Returns: The title for the specified section's header, or `nil` for no title.
open func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return nil
}
/// Returns the title for the specified section's footer.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - section: An index of section.
///
/// - Returns: The title for the specified section's footer, or `nil` for no title.
open func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return nil
}
/// Returns a cell for row at specified index path.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - indexPath: An index path for cell.
///
/// - Returns: A cell for row at specified index path.
open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let itemIdentifier = core.unsafeItemIdentifier(for: indexPath)
guard let cell = cellProvider(tableView, indexPath, itemIdentifier) else {
universalError("UITableView dataSource returned a nil cell for row at index path: \(indexPath), tableView: \(tableView), itemIdentifier: \(itemIdentifier)")
}
return cell
}
/// Returns whether it is possible to edit a row at given index path.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - section: An index of section.
///
/// - Returns: A boolean for row at specified index path.
open func tableView(_ tableView: UITableView, canEditRowAt: IndexPath) -> Bool {
return false
}
/// Returns whether it is possible to move a row at given index path.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - section: An index of section.
///
/// - Returns: A boolean for row at specified index path.
open func tableView(_ tableView: UITableView, canMoveRowAt _: IndexPath) -> Bool {
return false
}
/// Performs the edit action for a row at given index path.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - editingStyle: An action for given edit action.
/// - indexPath: An index path for cell.
///
/// - Returns: Void.
open func tableView(_ tableView: UITableView, commit _: UITableViewCell.EditingStyle, forRowAt _: IndexPath) {
// Empty implementation.
}
/// Moves a row at given index path.
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - source: An index path for given cell position.
/// - target: An index path for target cell position.
///
/// - Returns: Void.
open func tableView(_ tableView: UITableView, moveRowAt _: IndexPath, to _: IndexPath) {
// Empty implementation.
}
/// Return list of section titles to display in section index view (e.g. "ABCD...Z#").
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
///
/// - Returns: The list of section titles to display.
open func sectionIndexTitles(for tableView: UITableView) -> [String]? {
return nil
}
/// Tell table which section corresponds to section title/index (e.g. "B",1)).
///
/// - Parameters:
/// - tableView: A table view instance managed by `self`.
/// - title: The title as displayed in the section index of tableView.
/// - section: An index number identifying a section title in the array returned by sectionIndexTitles(for tableView:).
///
/// - Returns: The list of section titles to display.
open func tableView(_ tableView: UITableView, sectionForSectionIndexTitle _: String, at section: Int) -> Int {
return section
}
}
#endif