I've implemented UITableView using UITableViewDiffableDataSource
and NSDiffableDataSourceSnapshot
like
private typealias ListDataSource = UITableViewDiffableDataSource<Section, Wrapper>
private typealias ListSnapshot = NSDiffableDataSourceSnapshot<Section, Wrapper>
enum Wrapper: Hashable {
case one([Company])
case two([Member])
}
private enum Section: CaseIterable {
case main
}
private func configureDataSource() {
dataSource = ListDataSource(tableView: listTableView,
cellProvider: { [weak self] (_, indexPath, wrapper) -> UITableViewCell? in
guard let `self` = self else {
return UITableViewCell()
}
switch wrapper {
case .one(let company):
let cell = self.listTableView.dequeueReusableCell(withIdentifier: "Cell",
for: indexPath)
cell.textLabel?.text = company[indexPath.row].name
return cell
case .two(let member):
let cell = self.listTableView.dequeueReusableCell(withIdentifier: "Cell",
for: indexPath)
cell.textLabel?.text = member[indexPath.row].name.first
return cell
}
})
}
func updateData(_ wrapper: Wrapper) {
var snapshot = ListSnapshot()
snapshot.appendSections([.main])
switch wrapper {
case .one(let comp):
snapshot.appendItems([.one(comp)])
dataSource.apply(snapshot, animatingDifferences: true)
case .two(let member):
snapshot.appendItems([.two(member)])
dataSource.apply(snapshot, animatingDifferences: true)
}
}
on segment change, updating data respective of Wrapper type. But the issue is only one record displayed every time.
func handleSegmentChanged(_ sender: UISegmentedControl) {
let member = Member(name: Name(first: "Harshal", last: "Wani"),
memberId: "123", age: 30, email: "harshal@gmail.com", phone: "123456789")
let member2 = Member(name: Name(first: "David", last: "John"),
memberId: "123", age: 30, email: "harshal@gmail.com", phone: "123456789")
let comp = Company(name: "Comp 1", companyId: "", website: "", logo: "", about: "", members: [member, member2])
let comp2 = Company(name: "Comp 2", companyId: "", website: "", logo: "", about: "", members: [member, member2])
if sender.selectedSegmentIndex == 0 {
updateData(.one([comp, comp2]))
} else {
updateData(.two(comp.members))
}
}
Appreciate for any help, thanks
You are applying only one item per section, you have to declare the wrapper
enum Wrapper: Hashable {
case one(Company)
case two(Member)
}
In handleSegmentChanged
create an array of Wrapper
items instead of one Wrapper
with an array of associated types.
@IBAction func handleSegmentChanged(_ sender: UISegmentedControl) {
let member = Member(name: Name(first: "Harshal", last: "Wani"), memberId: "123", age: 30, email: "harshal@gmail.com", phone: "123456789")
let member2 = Member(name: Name(first: "David", last: "John"), memberId: "123", age: 30, email: "harshal@gmail.com", phone: "123456789")
let comp = Company(name: "Comp 1", companyId: "", website: "", logo: "", about: "", members: [member, member2])
let comp2 = Company(name: "Comp 2", companyId: "", website: "", logo: "", about: "", members: [member, member2])
if sender.selectedSegmentIndex == 0 {
updateData([.one(comp), .one(comp2)])
} else {
updateData(comp.members.map{.two($0)})
}
}
And replace updateData
with
func updateData(_ wrapper: [Wrapper]) {
var snapshot = ListSnapshot()
snapshot.appendSections([.main])
snapshot.appendItems(wrapper)
dataSource.apply(snapshot, animatingDifferences: true)
}
The [weak self] -> self
dance in configureDataSource
is nonsense. The first parameter of the closure is the table view. Use this instance to avoid any occurrence of self
and replace configureDataSource
with
private func configureDataSource() {
dataSource = ListDataSource(tableView: listTableView,
cellProvider: { (tableView, indexPath, wrapper) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell",
for: indexPath)
switch wrapper {
case .one(let company):
cell.textLabel?.text = company.name
case .two(let member):
cell.textLabel?.text = member.name.first
}
return cell
})
}