Trying to implement the IGListKit library, I'm running into the issue that my cells are updated unnecessarily. I'm using a singleton adapter.dataSource with one section per row in the table.
Minimum example:
import IGListKit
class ContentItem: ListDiffable {
weak var item: Content?
weak var section: ContentSectionController?
func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
return true
}
init(item: Content?) {
self.item = item
}
}
class ContentSectionController: ListSectionController {
weak var object: ContentItem?
override func didUpdate(to object: Any) {
self.object = object as? ContentItem
self.object?.section = self
// should only be called on updates
}
override func sizeForItem(at index: Int) -> CGSize {
guard let content = object?.item else {
return CGSize(width: 0, height: 0)
}
// calculate height
}
override func cellForItem(at index: Int) -> UICollectionViewCell {
let cell = collectionContext!.dequeueReusableCellFromStoryboard(withIdentifier: "ContentCell", for: self, at: index)
(cell as? ContentCell)?.item = object // didSet will update cell
return cell
}
override init() {
super.init()
self.workingRangeDelegate = self
}
}
extension ContentSectionController: ListWorkingRangeDelegate {
func listAdapter(_ listAdapter: ListAdapter, sectionControllerWillEnterWorkingRange sectionController: ListSectionController) {
// prepare
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerDidExitWorkingRange sectionController: ListSectionController) {
return
}
}
class ContentDataSource: NSObject {
static let sharedInstance = ContentDataSource()
var items: [ContentItem] {
return Content.displayItems.map { ContentItem(item: $0) }
}
}
extension ContentDataSource: ListAdapterDataSource {
func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return items
}
func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
return ContentSectionController()
}
func emptyView(for listAdapter: ListAdapter) -> UIView? {
return nil
}
}
/// VC ///
class ContentViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let updater = ListAdapterUpdater()
adapter = ListAdapter(updater: updater, viewController: self, workingRangeSize: 2)
adapter.collectionView = collectionView
adapter.dataSource = ContentDataSource.sharedInstance
}
var adapter: ListAdapter!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
adapter.performUpdates(animated: true)
}
// ...
}
On every view appear I call adapter.performUpdates(animated: true), which should never update the cells since isEqual is overridden with true. Nonetheless, all cells' didUpdate is triggered, calling cellForItem again too.
IGListKit requires both
diffIdentifierandisEqualto be implemented with the IGListDiffable protocol in order to compare the identity/equality of two objects. (You're missing the diff identifier in your model).My understanding is that under the hood, ListKit checks to see if the two diff identifiers of the objects are equal, if they are THEN it moves on to comparing them with
isEqual.Resources: IGListKit Best Practices IGListDiffable Protocol Reference