具有自定义集合视图布局的可区分数据源?

Diffable Data Source with a custom collection view layout?

Here I have created a sample app that uses diffable data source for a collection view with a custom collection view layout. The specific layout I am using is from this教程。

如果您不想克隆存储库并自己尝试,这里是代码的相关部分。

import UIKit
let cellIdentifier = "testRecordCell"

struct Record:Hashable {
    let identifier = UUID()
    func hash(into hasher: inout Hasher) {
        hasher.combine(identifier)
    }
    static func == (lhs: Record, rhs: Record) -> Bool {
        return lhs.identifier == rhs.identifier
    }
    var timeStamp: Date
    init(daysBack: Int){
        self.timeStamp = Calendar.current.date(byAdding: .day, value: -1*daysBack, to: Date())!
    }
}
class Cell:UICollectionViewCell {
}

class Section: Hashable {
  var id = UUID()
  // 2
  var records:[Record]
  
  init(records:[Record]) {
    self.records = records
  }
  
  func hash(into hasher: inout Hasher) {
    hasher.combine(id)
  }
  
  static func == (lhs: Section, rhs: Section) -> Bool {
    lhs.id == rhs.id
  }
}

extension Section {
  static var allSections: [Section] = [
    Section(records: [
      Record(daysBack: 5),Record(daysBack: 6)
    ]),
    Section(records: [
      Record(daysBack: 3)
    ])
    ]
}

class ViewController: UICollectionViewController {

    private lazy var dataSource = makeDataSource()
    private var sections = Section.allSections

    fileprivate typealias DataSource = UICollectionViewDiffableDataSource<Section,Record>
    fileprivate typealias DataSourceSnapshot = NSDiffableDataSourceSnapshot<Section,Record>
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.collectionView?.register(Cell.self, forCellWithReuseIdentifier: cellIdentifier)
        applySnapshot()
        if let layout = collectionView.collectionViewLayout as? PinterestLayout {
            layout.delegate = self
        }
    }
}
extension ViewController {
    
    fileprivate func makeDataSource() -> DataSource {
        let dataSource = DataSource(
            collectionView: self.collectionView,
            cellProvider: { (collectionView, indexPath, testRecord) ->
              UICollectionViewCell? in
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellIdentifier, for: indexPath)
                cell.backgroundColor = .black
                return cell
            })
        return dataSource
    }
    func applySnapshot(animatingDifferences: Bool = true) {
        // 2
        var snapshot = DataSourceSnapshot()
        snapshot.appendSections(sections)
        sections.forEach { section in
          snapshot.appendItems(section.records, toSection: section)
        }
        //This part errors out: "request for number of items in section 0 when there are only 0 sections in the collection view"
        dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
    }
}
extension ViewController: PinterestLayoutDelegate {
    func collectionView(_ collectionView: UICollectionView, heightForPhotoAtIndexPath indexPath: IndexPath) -> CGFloat {
        return CGFloat(10)
    }
}

不知何故,布局没有注册集合视图中确实有项目和部分。当你 运行 它正常时,当你尝试应用快照时它会出错:“当集合视图中只有 0 个部分时,请求第 0 部分中的项目数”

然后,在 Pinterest 布局的 prepare() 函数中,当我设置断点并检查 collectionView.numberOfSections() 它 returns 0 时。所以不知何故快照没有与集合通信看法。请注意,我从不使用 collectionView 的委托方法 numberOfSections,因为我使用的是 diffable 数据源...

我的印象是 diffable 数据源通常与组合布局一起使用,尽管我在任何地方都没有看到这是一个要求。

那么有什么办法可以做到这一点吗?

问题出在这一行:

func applySnapshot(animatingDifferences: Bool = true) {

true更改为false,您就不会再崩溃了。

嗨,现在回答已经太晚了,但我尝试了同样的方法和同样的问题

我的案例问题是在 collectionView 中处理 numberOfItems

下方 PinterestLayout 中的 82 行 “对于项目 0..

所以..我将快照中的实际 numberOfItems 从视图注入到自定义布局

myLayout.updateNumberOfItems(currentSnapshot.numberOfItems)
dataSource.apply(currentSnapshot)

并且只使用 numberOfItems 而不是 collectionView.numberOfItems。

对我有用

如果我错了请告诉我,谢谢")