IGListKit icon indicating copy to clipboard operation
IGListKit copied to clipboard

ListSectionController's didUpdate and cellForItem re-called, even though isEqual == true

Open yspreen opened this issue 4 years ago • 0 comments

New issue checklist

  • [x] I have reviewed the README and documentation
  • [x] I have searched existing issues and this is not a duplicate
  • [x] I have attempted to reproduce the issue and include an example project.

General information

  • IGListKit version: master
  • iOS version(s): 13.6
  • CocoaPods/Carthage version: Carthage latest
  • Xcode version: 11.6
  • Devices/Simulators affected: iPhone device and simulator
  • Reproducible in the demo project? (Yes/No): No?
  • Related issues: -

Debug information

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.

yspreen avatar Jul 28 '20 13:07 yspreen