i found something really odd in NSDiffableDataSourceSnapshot behaviour. the tl;dr version is that this:
snapshot.moveItem("one", afterItem: "two")
dataSource.apply(snapshot)
gives correct result, while this:
var snapshotCopy = snapshot
snapshotCopy.moveItem("one", afterItem: "two")
dataSource.apply(snapshotCopy)
gives incorrect result, despite being semantically equivalent. snapshot is a true value type, right?
it is as odd as if i wrote:
var b = a
b += 1
a = b
and got a different result in "a" compared to "a += 1"
minimal source fragment attached (doesn't need nib files/storyboards)
========
snapshot.moveItem("one", afterItem: "two")
dataSource.apply(snapshot)
gives correct result, while this:
var snapshotCopy = snapshot
snapshotCopy.moveItem("one", afterItem: "two")
dataSource.apply(snapshotCopy)
gives incorrect result, despite being semantically equivalent. snapshot is a true value type, right?
it is as odd as if i wrote:
var b = a
b += 1
a = b
and got a different result in "a" compared to "a += 1"
minimal source fragment attached (doesn't need nib files/storyboards)
========
Code Block import UIKit class ViewController: UIViewController { var tv: UITableView! var dataSource: UITableViewDiffableDataSource<String, String>! override func viewDidLoad() { super.viewDidLoad() tv = UITableView(frame: view.bounds) tv.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(tv) tv.register(UITableViewCell.self, forCellReuseIdentifier: "cell") var originalSnapshot = NSDiffableDataSourceSnapshot<String, String>() originalSnapshot.appendSections(["***"]) originalSnapshot.appendItems(["one", "two", "three"]) dataSource = UITableViewDiffableDataSource<String, String>(tableView: tv) { (tv, indexPath, item) -> UITableViewCell? in let cell = tv.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = item return cell } dataSource.apply(originalSnapshot) DispatchQueue.main.asyncAfter(deadline: .now() + 2) { var snapshot = self.dataSource.snapshot() snapshot.insertItems(["four"], afterItem: "one") if true { var snapshotCopy = snapshot snapshotCopy.moveItem("one", afterItem: "two") self.dataSource.apply(snapshotCopy) /* gives incorrect result: two, one, three */ } else { snapshot.moveItem("one", afterItem: "two") self.dataSource.apply(snapshot) /* gives correct result: four, two, one, three */ } } } } @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { window = UIWindow(frame: UIScreen.main.bounds) window!.rootViewController = ViewController() window!.makeKeyAndVisible() return true } }