ra1028 / DifferenceKit

💻 A fast and flexible O(n) difference algorithm framework for Swift collection.

Home Page:https://ra1028.github.io/DifferenceKit

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cells rendered incorrectly when using `UITableView.reload(using:, with:)` under certain contexts

OliverPearmain opened this issue · comments

Checklist

Given

An original list of three elements.

Component(title: "Shuffle Emojis", subtitle: "Shuffle sectioned Emojis in UICollectionView"),
Component(title: "Header Footer Section", subtitle: "Update header/footer by reload section in UITableView"),
Component(title: "Random", subtitle: "Random diff in UICollectionView")

If the list is updated so that the...

  • middle element is updated
  • first element is moved to the end

The resulting changeset will look like...

[
    Changeset(
        data: [
            Component(title: "Shuffle Emojis", subtitle: "Shuffle sectioned Emojis in UICollectionView"),
            Component(title: "Header Footer Section", subtitle: "XXX Update header/footer by reload section in UITableView"),
            Component(title: "Random", subtitle: "Random diff in UICollectionView")
        ],
        elementUpdated: [
            [element: 1, section: 0]
        ]
    ),
    Changeset(
        data: [
            Component(title: "Header Footer Section", subtitle: "XXX Update header/footer by reload section in UITableView"),
            Component(title: "Random", subtitle: "Random diff in UICollectionView"),
            Component(title: "Shuffle Emojis", subtitle: "Shuffle sectioned Emojis in UICollectionView")
        ],
        elementMoved: [
            (source: [element: 1, section: 0], target: [element: 0, section: 0]),
            (source: [element: 2, section: 0], target: [element: 1, section: 0])
        ]
    )
]

When

I apply this changeset to the UITableView with reload(using:, with:)...

Expected Behavior

The cells should animate appropriately and the cells should all be in their new positions with their updated values.

Current Behavior

Cells at index 0 and 1 are identical. Element 0 (originally 1) is not present in the UITableView.

Steps to Reproduce

I've modified the demo app in a fork to demonstrate the issue.

  1. Checkout https://github.com/OliverPearmain/DifferenceKit/tree/reload-with-move-bug
  2. Run the demo app
  3. The changeset will automatically be applied to the initial view contoller (so don't navigate anywhere, just watch the animation and resulting UITableView).

Detailed Description (Include Screenshots)

Please note that the "context" under which this happens is important because an identifcal changeset may not result in the same problem.

For instance, in the example code, if I rename the HomeViewController's components stored property to data then the problem goes away, WTF! The naming of properties should not affect the resulting animation, this is most peculiar. Demo code.

Reproducible Demo Project

https://github.com/OliverPearmain/DifferenceKit/tree/reload-with-move-bug

Environments

  • Library version: 1.1.5
  • Swift version: Swift 5
  • iOS version: 13.3
  • Xcode version: 11.3.1
  • Devices/Simulators: iPhone 11 - 13.3 Simulator
  • CocoaPods/Carthage version: n/a

@OliverPearmain

I checked your demo.
You seem to be using reload(using:with:) method incorrectly.
DifferenceKit applies the diffs in several stages, so you should set the data that passed to the setData closure to var components, like below.

let components = [
    Component(title: "Header Footer Section", subtitle: "XXX Update header/footer by reload section in UITableView"),
    Component(title: "Random", subtitle: "Random diff in UICollectionView"),
    Component(title: "Shuffle Emojis", subtitle: "Shuffle sectioned Emojis in UICollectionView"),
]
     
let changeset = StagedChangeset(source: self.components, target: components)
tableView.reload(using: changeset, with: .fade) { data in
    self.components = data
}

Aha, bingo. 🤦‍♂ Thanks so much.