具有多种单元格类型的 DiffableDataSource

Jas*_*ore 11 uitableview uikit uicollectionview ios13 diffabledatasource

我正在查看 iOS13 中可用的 DiffableDataSource(或在此处向后移植:https : //github.com/ra1028/DiffableDataSources)并且无法弄清楚如何在您的集合或 tableview 中支持多种单元格类型。

Apple 的示例代码1具有:

var dataSource: UICollectionViewDiffableDataSource<Section, OutlineItem>! = nil
Run Code Online (Sandbox Code Playgroud)

这似乎强制数据源为单个单元格类型。如果我为另一种单元格类型创建一个单独的数据源 - 那么不能保证两个数据源不会同时apply调用它们 - 这会导致可怕的NSInternalInconsistencyException- 任何试图动画的人都熟悉使用 手动插入/删除单元格performBatchUpdates

我错过了一些明显的东西吗?

ofl*_*hra 15

I wrapped my different data in an enum with associated values. In my case, my data source was of type UICollectionViewDiffableDataSource<Section, Item>, where Item was

enum Item: Hashable {
  case firstSection(DataModel1)
  case secondSection(DataModel2)
}
Run Code Online (Sandbox Code Playgroud)

then in your closure passed into the data source's initialization, you get an Item, and you can test and unwrap the data, as needed.

(I'd add that you should ensure that your backing associated values are Hashable, or else you'll need to implement that. That is what the diff'ing algorithm uses to identify each cell, and resolve movements, etc)


Jas*_*ore 7

您肯定需要有一个单一的数据源。

关键是使用更通用的类型。SwiftAnyHashable在这里运行良好。并且您只需要将 的实例AnyHashable转换为更具体的类。

lazy var dataSource = CollectionViewDiffableDataSource<Section, AnyHashable> (collectionView: collectionView) { collectionView, indexPath, item in

        if let article = item as? Article, let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Section.articles.cellIdentifier, for: indexPath) as? ArticleCell {
            cell.article = article
            return cell
        }

        if let image = item as? ArticleImage, let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Section.trends.cellIdentifier, for: indexPath) as? ImageCell {
            cell.image = image
            return cell
        }

        fatalError()
    }
Run Code Online (Sandbox Code Playgroud)

部分枚举看起来像这样:

    enum Section: Int, CaseIterable {
        case articles
        case articleImages

        var cellIdentifier: String {
            switch self {
            case .articles:
                return "articleCell"
            case .articleImages:
                return "imagesCell"
            }
        }
    }

Run Code Online (Sandbox Code Playgroud)