首页 > 解决方案 > 具有自定义集合视图布局的 Diffable 数据源?

问题描述

在这里,我创建了一个示例应用程序,它将 diffable 数据源用于具有自定义集合视图布局的集合视图。我使用的特定布局来自教程。

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

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() 时,它返回 0。所以不知何故,快照没有与集合视图通信。请注意,我从不使用 collectionView 的委托方法 numberOfSections,因为我使用的是 diffable 数据源...

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

那么有没有办法做到这一点?

标签: iosswiftuicollectionviewuicollectionviewlayoutuicollectionviewdiffabledatasource

解决方案


问题是这一行:

func applySnapshot(animatingDifferences: Bool = true) {

更改truefalse,您将不再崩溃。


推荐阅读