Diffable datasources require specifying a SectionIdentifierType
and an ItemIdentifierType
and these types have to conform to Hashable
Supposedly they must conform to Hashable
so that the datasource can do its diffing.
So why does it behave differently depending on if the identifier type is a class or a struct even when the == and hash functions are the same? Or even the === function is overridden for classes so that it acts more like a value type?
Example:
import UIKit
public class DebugViewController: UIViewController {
typealias SectionType = IntWrapper
typealias ItemType = IntWrapper
public class IntWrapper: Hashable {
public static func == (lhs: DebugViewController.IntWrapper, rhs: DebugViewController.IntWrapper) -> Bool {
lhs.number == rhs.number
}
public static func === (lhs: DebugViewController.IntWrapper, rhs: DebugViewController.IntWrapper) -> Bool {
lhs.number == rhs.number
}
public func hash(into hasher: inout Hasher) {
hasher.combine(number)
}
var number: Int
init(number: Int) {
self.number = number
}
}
private var dataSource: UITableViewDiffableDataSource<SectionType, ItemType>!
@IBOutlet var tableView: UITableView!
public override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DefaultCell")
dataSource = UITableViewDiffableDataSource<SectionType, ItemType>(tableView: tableView) { (tableView, indexPath, item) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "DefaultCell")!
cell.textLabel?.text = "\(item.number)"
return cell
}
apply()
}
@IBAction func buttonTapped(_ sender: Any) {
apply()
}
func apply() {
var snapshot = NSDiffableDataSourceSnapshot<SectionType, ItemType>()
let sections = [IntWrapper(number: 0)]
let items = [IntWrapper(number: 1)]
snapshot.appendSections(sections)
sections.forEach { snapshot.appendItems( items, toSection: $0) }
dataSource.apply(snapshot, animatingDifferences: true)
}
}
If IntWrapper
is a struct the table view does nothing when apply()
is called (apply()
essentially loads in the same data) For me, this is the expected behavior.
If IntWrapper
is a class the table view reloads when apply() is called. Also, the hash()
and == functions are NOT even called.
I don't think this can be answered unless someone has access to the source (hint, hint) or unless I made some mistake in my example.
struct
s whenever possible. If the data can be identical for two structs when I add anlet id: UUID
to each struct so that they are always unique. If you get two structs with the same data the app will crash. If the data needs to be updated I create a new struct with the same id but change the values and add that to the new snapshot. – Epp