【Swift】Compositinal Layouts を複数の型に適応させる方法

こんにちは、しょーです。

前回、iOS13からのCollectionViewに使用できるCompositionalLayoutsのやり方を説明しました。

iOS13のCollectionView、CompositionalLayoutsでモダンにレイアウトする

今回は、複数のデータ型を一つのCollectionViewに適応させる(Multiple data types)ために一捻りさせないといけないので、そのTipsを紹介したいと思います。

行ってみましょう。

複数のデータ型を適応させるとは?

詳しくは上記のリンクで確認して欲しいのですが、CompositionalLayoutsで作成した各複数セクションを組み立てる場合、

var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()

というメソッドを使用してセクションを組み立てて行く必要があります。

struct ItemA: Hashable {
    let id: Int

    static func == (lhs: Item, rhs: Item) -> Bool {
        return lhs.id == rhs.id
    }
}

let itemAs: [ItemA] = {
    ItemA(id: 0),
    ItemA(id: 1),
    ItemA(id: 2),
    ItemA(id: 3)
}

let itemAs2: [ItemA] = {
    ItemA(id: 4),
    ItemA(id: 5),
    ItemA(id: 6),
    ItemA(id: 7)
}

  snapshot.appendSections([Section.applianceHorizontal])
  snapshot.appendItems(itemAs)

  snapshot.appendSections([Section.article])
  snapshot.appendItems(itemAs2)

  return snapshot

ですが、UICollectionViewDiffableDataSource や NSDiffableDataSourceSnapshot には一つの方しか指定できないため、snapshotで別々のデータ型を挿入したい場合困難になります。

ここのデータ型を、今回は複数対応できる型を作成して突っ込んでいきます。

enum:Hashable で解決する

そのような場合はenumを利用すると便利です。

利用する構造体はHashableに基づいている必要がありますが、挿入したい複数の型を取りまとめるHashableに適合したenumを作成します。

enum DiffableDatas: Hashable {
    case itemA(ItemA)
    case itemB(ItemB)
}

struct ItemA: Hashable {
    let id: Int

    static func == (lhs: Item, rhs: Item) -> Bool {
        return lhs.id == rhs.id
    }
}

struct ItemB: Hashable {
    let id: Int

    static func == (lhs: Item, rhs: Item) -> Bool {
        return lhs.id == rhs.id
    }
}

let itemAs: [ItemA] = {
    ItemA(id: 0),
    ItemA(id: 1),
    ItemA(id: 2),
    ItemA(id: 3)
}

let itemBs: [ItemB] = {
    ItemB(id: 0),
    ItemB(id: 1),
    ItemB(id: 2),
    ItemB(id: 3)
}

この enum DiffableDatas を型として当てはめることにより、snapshot生成時にcaseに書いてある型を適合させて使用することでできます。

private lazy var dataSource: UICollectionViewDiffableDataSource<Section, DiffableDatas>! = nil

private func snapshotForCurrentState() -> NSDiffableDataSourceSnapshot<Section, DiffableDatas> {
        var snapshot = NSDiffableDataSourceSnapshot<Section, DiffableDatas>()

        snapshot.appendSections([Section.firstSection])
        let itemsA = itemsAs.map { DiffableDatas.itemA($0) } // itemsA: [DiffableDatas] としてデータが入っている
        snapshot.appendItems(itemsA)

        snapshot.appendSections([Section.secondSection])
        let itemsB = itemsBs.map { DiffableDatas.itemB($0) } // itemsB: [DiffableDatas] としてデータが入っている
        snapshot.appendItems(itemsB)

        return snapshot
}

終わりに

今回は前回に引き続きCompositionalLayoutsのお話でした。
このようなTipsを知っていると、さらに汎用性のあるCollectionViewを作成できるかと思います!

今日はこんなところです!
以上お疲れっす!
じゃーな!