General purpose, fast diff algorithm supporting [m] level nested diffs.
pod 'FastDiff'
And then in the terminal pod update
. If you are new to cocoapods please check out Cocoapods Installation
Declare the dependency in the swift Package.swift
file like such:
dependencies: [
///.... other deps
.package(url: "https://www.github.com/kandelvijaya/FastDiff", from: "1.0.0"),
]
Execute the update command swift package update
and then swift package generate-xcodeproj
.
Go to the source directory, and run:
$ swift test
let oldModels = ["apple", "microsoft"]
let newModels = ["apple", "microsoft", "tesla"]
/// Algorithm
let changeSet = diff(oldModels, newModels)
// [.addition("tesla", at: 2)]
/// Verification
oldModels.merged(with: changeSet) == newModels
// true
Note that diff
produces changeset that can't be merged into old collections as is, most of the times.
The changeset has to be ordered
in-order for successful merge. This is also useful if you want to
apply changeset to UITableView
or UICollectionView
.
let chnageSet = diff(["A","B"], [āCā,"D"])
// [.delete("A",0), .delete("B",1), .add("C",0), .add(āD",1)]
let orderedChangeSet = orderedOperation(from: changeSet)
// [.delete("B",1), .delete("A",0), .add("C",0), .add("D",1)]
Struct
's. Please refrain from using reference type (Class
instance). When you must use class instance / object, you might get more updates than you expect. If you want to resolve this issue for your use case please DM me www.twitter.com/kandelvijayadiffAllLevel(,)
Please check out this presentation slides that I gave at @mobiconf 2018
Say you got a list of Component where each is defined as:
struct Component {
let title: String
let footer: FooterViewModel? // useful on top levels
let children: [Component]? // nil when its a leaf.
let icons_sf: [String]
}
Say we got this model represented in the UI using CollectionView sections. Today
and Tomorrow
are represented by SectionHeaderSupplemenratyViews and so are corresponding footers. The internalItems are represented by TaskCell
. User has the ability to add new task using NavBar Button.
let old = [
Component(title: "Today", footer: .init(), icons_sf: ["1.fill", "2.circle"], children: [
Component(title: "Go to supermarket", footer: nil, icons_sf: ["sf.cucumber"], children: nil),
Component(title: "Make breakfast", footer: nil, icons_sf: ["sf.avocado"], children: nil)
]),
Component(title: "Tomorrow", footer: .init(), icons_sf: ["1.fill", "2.circle"], children: [
Component(title: "Work on FastDiff", footer: nil, icons_sf: ["sf.chopsticks"], children: nil),
Component(title: "SwiftUI TODO list for macos", footer: nil, icons_sf: ["sf.pen"], children: nil)
])
]
Say user adds a new task item to Todays entry therefore changing the new model becomes:
let new = [
Component(title: "Today", footer: .init(), icons_sf: ["1.fill", "2.circle"], children: [
Component(title: "Go to supermarket", footer: nil, icons_sf: ["sf.cucumber"], children: nil),
Component(title: "Make breakfast", footer: nil, icons_sf: ["sf.avocado"], children: nil),
/// newly added
Component(title: "Buy PS5 from amazon", footer: nil, icons_sf: ["sf.play"], children: nil),
]),
Component(title: "Tomorrow", footer: .init(), icons_sf: ["1.fill", "2.circle"], children: [
Component(title: "Work on FastDiff", footer: nil, icons_sf: ["sf.chopsticks"], children: nil),
Component(title: "SwiftUI TODO list for macos", footer: nil, icons_sf: ["sf.pen"], children: nil)
])
]
We assume Component: Diffable
diff(old, new)
?There can be 2 potential solutions:
[.delete(item: old.0, at: 0), insert(item: new.0, at 0)]
extension Component: Diffable {}
[.update(at: 0, old: old.0, new: new.0)]
extension Component: Diffable, Equatable {
var diffHash: Int {
/// excludes innerDiffItems
return title.hashValue ^ footer.hashValue ^ icons_sf.hashValue
}
var innerDiffableItems: [Component] {
return children ?? []
}
}
.update(,,,)
on section level, we can perform diff on internal items like so diff(old.innerDiffableItems, new.innerDiffableItems)
to receive exact changes on cell level which can then be patched to section.performBatchUpdate
This project is licensed under the MIT License - see the LICENSE.md file for details
link |
Stars: 35 |
Last commit: 4 weeks ago |
Swiftpack is being maintained by Petr Pavlik | @ptrpavlik | @swiftpackco | API | Analytics