IOS list diff library DifferenceKit example

1. Install by adding this in your cocoapods Podfie and run pod install from the command line windown in your project directory.

pod 'DifferenceKit'

2. We need to wrap the data in ArraySection. ArraySection is provided by the DifferenceKit.

3. We need to implement the Differentiable for the data items that will be put into the ArraySection.

4. Here is the source code for the Differentiable protocol.

/// Represents the value that identified for differentiate.
public protocol Differentiable: ContentEquatable {
    /// A type representing the identifier.
    associatedtype DifferenceIdentifier: Hashable

    /// An identifier value for difference calculation.
    var differenceIdentifier: DifferenceIdentifier { get }
}

public extension Differentiable where Self: Hashable {
    /// The `self` value as an identifier for difference calculation.
    @inlinable
    var differenceIdentifier: Self {
        return self
    }
}

5. Here is an example of implementing the Differentiable on enum and String.

private enum EmoticonSectionID: Differentiable, CaseIterable {
    case first, second, third
}

extension String: Differentiable {}

6. Here is an example of implementing the Differentiable on a custom object class.

private struct RandomModel: Differentiable {
    var id: UUID
    var isUpdated: Bool
    
    var differenceIdentifier: UUID {
        return id
    }
    
    init(_ id: UUID = UUID(), _ isUpdated: Bool = false) {
        self.id = id
        self.isUpdated = isUpdated
    }
    
    func isContentEqual(to source: RandomModel) -> Bool {
        return isUpdated == source.isUpdated
    }
}

7. Here is an example of wrapping the data items in ArraySection and update the collectionView when the data is changed.

private enum EmoticonSectionID: Differentiable, CaseIterable {
    case first, second, third
}

private typealias EmoticonSection = ArraySection

private var data = [EmoticonSection]()

private var dataInput: [EmoticonSection] {
    get { return data }
    set {
        // whenever this dataInput gets assigned a new data, this block of code will run and update the collectionView or tableView with the new changes in the data set.
        let changeset = StagedChangeset(source: data, target: newValue)
        collectionView.reload(using: changeset) { data in
            self.data = data
        }
    }
}

let ids = EmoticonSectionID.allCases
let emoticons = (0x1F600...0x1F647).compactMap { UnicodeScalar($0).map(String.init) }
let splitedCount = Int((Double(emoticons.count) / Double(ids.count)).rounded(.up))

dataInput = ids.enumerated().map { offset, model in
    let start = offset * splitedCount
    let end = min(start + splitedCount, emoticons.endIndex)
    let emoticons = emoticons[start..

8. The UICollectionViewDataSource and UICollectionViewDelegate protocol will just the data object normally like below.

extension ShuffleEmoticonViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return data.count
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data[section].elements.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EmoticonCollectionViewCell.reuseIdentifier, for: indexPath) as! EmoticonCollectionViewCell
        let emoticon = data[indexPath.section].elements[indexPath.item]
        cell.emoticon = emoticon
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        guard kind == UICollectionView.elementKindSectionHeader else {
            return UICollectionReusableView()
        }
        
        let view = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: TextCollectionReusableView.reuseIdentifier, for: indexPath) as! TextCollectionReusableView
        view.text = "Section \(data[indexPath.section].model)"
        return view
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        remove(at: indexPath)
    }
}

Complete example in Github
DifferenceKit in Github

Search within Codexpedia

Custom Search

Search the entire web

Custom Search