【问题标题】:IGListSectionController's didUpdate and cellForItem always re-called, even though isEqual == trueIGListSectionController 的 didUpdate 和 cellForItem 总是被调用,即使 isEqual == true
【发布时间】:2024-01-16 15:34:01
【问题描述】:

尝试实现 IGListKit 库时,我遇到了我的单元格被不必要地更新的问题。我正在使用单例adapter.dataSource,表格中每行一个部分。

最小示例:

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)
  }
  // ...
}

在每个视图出现时,我都会调用adapter.performUpdates(animated: true),它不应该更新单元格,因为isEqualtrue 覆盖。尽管如此,所有单元格的didUpdate 都被触发,再次调用cellForItem

【问题讨论】:

    标签: swift uicollectionview iglistkit


    【解决方案1】:

    IGListKit 需要使用 IGListDiffable 协议实现 diffIdentifierisEqual,以便比较两个对象的身份/相等性。 (您的模型中缺少差异标识符)。

    我的理解是,在后台,ListKit 会检查对象的两个差异标识符是否相等,如果相等,则继续将它们与 isEqual 进行比较。

    资源: IGListKit Best Practices IGListDiffable Protocol Reference

    【讨论】:

      最近更新 更多