ra1028 / DifferenceKit

💻 A fast and flexible O(n) difference algorithm framework for Swift collection.
https://ra1028.github.io/DifferenceKit
Apache License 2.0
3.54k stars 239 forks source link

How to use DifferenceKit with diffable data sources? #160

Open tinder-cfuller opened 4 months ago

tinder-cfuller commented 4 months ago

Checklist

Detailed Description

How to use DifferenceKit with diffable data sources?

let stagedChangeset = StagedChangeset(source: dataStore.elements, target: newElements)

for changeset in stagedChangeset {

    dataStore.elements = changeset.data

    var snapshot = dataSource.snapshot()

    // What to do here?

    dataSource.apply(snapshot, animatingDifferences: true)
}

While each element can be Identifiable to provide identifiers for the various snapshot methods, it is not clear how to process the changesets.

Please explain in detail how to accomplish this or kindly consider adding methods to the library similar to the existing UIKit/AppKit extensions. Thank you!

tinder-cfuller commented 4 months ago

The temporary workaround shown below replaces all the identifiers and appears to work, however I am still seeking a solution to apply the deleted/inserted/updated/moved sections and elements for optimum performance.

extension NSDiffableDataSourceSnapshot {

    // MARK: - With Sections

    public mutating func apply<T, U>(
        _ changeset: Changeset<[ArraySection<T, U>]>
    ) where T: Identifiable, T.ID == SectionIdentifierType, U: Identifiable, U.ID == ItemIdentifierType {
        deleteAllItems()
        appendSections(changeset.data.map(\.model).map(\.id))
        for arraySection: ArraySection in changeset.data {
            appendItems(arraySection.elements.map(\.id), toSection: arraySection.model.id)
        }
        reloadSections(changeset.sectionUpdated.map { offset in
            sectionIdentifiers[offset]
        })
        let items: [ItemIdentifierType] = changeset.elementUpdated.map { path in
            itemIdentifiers(inSection: sectionIdentifiers[path.section])[path.element]
        }
        if #available(iOS 15.0, *) {
            reconfigureItems(items)
        } else {
            reloadItems(items)
        }
    }

    // MARK: - Without Sections

    public mutating func apply<T>(
        _ changeset: Changeset<T>
    ) where SectionIdentifierType == Int, T.Element: Identifiable, T.Element.ID == ItemIdentifierType {
        deleteAllItems()
        appendSections([0])
        appendItems(changeset.data.map(\.id))
        let items: [ItemIdentifierType] = changeset.elementUpdated.map { path in
            itemIdentifiers[path.element]
        }
        if #available(iOS 15.0, *) {
            reconfigureItems(items)
        } else {
            reloadItems(items)
        }
    }
}
tinder-cfuller commented 3 weeks ago

Hello @ra1028

May you please consider following up on this GitHub issue? It would be very much appreciated.

Thank you!