Skip to content

Commit

Permalink
Use absolute path for link in README
Browse files Browse the repository at this point in the history
  • Loading branch information
ra1028 committed Aug 3, 2018
1 parent a161d45 commit bf77721
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 125 deletions.
1 change: 1 addition & 0 deletions DifferenceKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Pod::Spec.new do |spec|
spec.version = '0.1.0'
spec.author = { 'ra1028' => '[email protected]' }
spec.homepage = 'https://github.com/ra1028/DifferenceKit'
spec.documentation_url = 'https://ra1028.github.io/DifferenceKit'
spec.summary = 'A fast and flexible O(n) difference algorithm framework for Swift collection.'
spec.description = <<-DESC
A fast and flexible O(n) difference algorithm framework for Swift collection.
Expand Down
105 changes: 54 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,45 +16,45 @@ The algorithm is optimized based on the Paul Heckel's algorithm.

---

<div style="text-align:center">
<img src="./assets/Sample.gif" width="250">
</div>

---

## Features
Calculate commands for batch-updates of UITableView and UICollectionView automatically
Automate to calculate commands for batch-updates of UITableView and UICollectionView
**O(n)** difference algorithm optimized for performance in Swift
✅ Supports both linear and sectioned collection
✅ Supports calculating differences with best effort even if elements or section contains duplicates
✅ Supports **all commands** for animating UI batch-updates including section reloads

---

<p align="center">
<img src="https://raw.githubusercontent.com/ra1028/DifferenceKit/master/assets/sample.gif" width="250">
</p>

---

## Algorithm
The algorithm is optimized based on the Paul Heckel's algorithm.
See also his paper [A technique for isolating differences between files]() released in 1978.
The algorithm used in DifferenceKit is optimized based on the Paul Heckel's algorithm.
See also his paper ["A technique for isolating differences between files"](https://dl.acm.org/citation.cfm?id=359467) released in 1978.
[RxDataSources](https://github.com/RxSwiftCommunity/RxDataSources) and [IGListKit](https://github.com/Instagram/IGListKit) are also implemented based on his algorithm.
This allows all types of differences to be computed in linear time **O(n)**.

However, in `performBatchUpdates` of UITableView and UICollectionView, there are combinations of commands that cause crash when applied simultaneously.
To solve this problem, DifferenceKit takes an approach of split the set of differences at the minimal stages that can be perform batch-updates with no crashes.

Implementation is [here]().
Implementation is [here](https://github.com/ra1028/DifferenceKit/blob/master/Sources/Algorithm.swift).

---

## Documentation
See docs in [GitHub Pages]().
See docs in [GitHub Pages](https://ra1028.github.io/DifferenceKit/).
Documentation is generated by [jazzy](https://github.com/realm/jazzy).

---

## Getting Started
- [Example app](./Examples)
- [Playground](./DifferenceKit.playground/Contents.swift)
- [Example app](https://github.com/ra1028/DifferenceKit/blob/master/Examples)
- [Playground](https://github.com/ra1028/DifferenceKit/blob/master/DifferenceKit.playground/Contents.swift)

### Example codes:
### Example codes
The type of the element that to take the differences must be conform to the `Differentiable` protocol:
```swift
struct User: Differentiable {
Expand All @@ -73,8 +73,7 @@ struct User: Differentiable {

In the case of definition above, `id` uniquely identifies the element and get to know the user updated by comparing `name` of the elements in source and target.

There are default implementations of `Differentiable` for the types that conformed to `Equatable` or `Hashable`.
However, `isUpdated(from:)` is always returns `false` on the algorithm in default, so you can't know the update:
There are default implementations of `Differentiable` for the types that conformed to `Equatable` or `Hashable`
```swift
extension String: Differentiable {}
```
Expand All @@ -93,7 +92,8 @@ let target = [

let changeset = StagedChangeset(source: source, target: target)
```
If you want to include multiple types conformed to Differentiable in the collection, use AnyDifferentiable:

If you want to include multiple types conformed to `Differentiable` in the collection, use `AnyDifferentiable`:
```swift
let source = [
AnyDifferentiable("A"),
Expand All @@ -114,7 +114,7 @@ let source: [Section<Model, String>] = [
Section(model: .b, elements: ["C"])
]
let target: [Section<Model, String>] = [
Section(model: .c, elements: ["D", "E"])
Section(model: .c, elements: ["D", "E"]),
Section(model: .a, elements: ["A"]),
Section(model: .b, elements: ["B", "C"])
]
Expand All @@ -141,87 +141,90 @@ collectionView.reload(using: changeset, interrupt: { $0.changeCount > 100 }) { d
---

## Comparison with Other Frameworks
Made a fair comparison as much as possible in features and performance with other popular and awesome frameworks.
Made a fair comparison as much as possible in features and performance with other **popular** and **awesome** frameworks.
The frameworks and its version that compared is below.

- [DifferenceKit](https://github.com/ra1028/DifferenceKit) - 0.1.0
- [RxDataSources](https://github.com/RxSwiftCommunity/RxDataSources) ([Differentiator](https://github.com/RxSwiftCommunity/RxDataSources/tree/master/Sources/Differentiator)) - 3.0.2
- [IGListKit](https://github.com/Instagram/IGListKit) - 3.4.0
- [ListDiff](https://github.com/lxcid/ListDiff) - 0.1.0
- [DeepDiff](https://github.com/onmyway133/DeepDiff) - 1.2.0
- [Differ](https://github.com/tonyarnold/Differ) ([Diff.swift](https://github.com/wokalski/Diff.swift)) - 1.2.3
- [Dwifft](https://github.com/jflinter/Dwifft) - 0.8

### Features comparison
- Supported collection
`Linear` means 1-dimensional collection.
`Sectioned` means 1-dimensional collection.

#### - Supported collection
| |Linear|Sectioned|Duplicate Element/Section|
|:------------|:-----|:-------:|:-----------------------:|
|:------------|:----:|:-------:|:-----------------------:|
|DifferenceKit||||
|RxDataSources||||
|IGListKit ||||
|ListDiff ||||
|DeepDiff ||||
|Differ ||||
|Dwifft ||||

- Supported element differences

| |Delete|Insert|Move|Reload|
|:------------|:-----|:----:|:--:|:----:|
|DifferenceKit|||||
|RxDataSources|||||
|IGListKit |||||
|ListDiff |||||
|Differ |||||
|Dwifft |||||

- Supported section differences
`Linear` means 1-dimensional collection.
`Sectioned` means 1-dimensional collection.

#### - Supported element differences
| |Delete|Insert|Move|Reload |
|:------------|:----:|:----:|:--:|:------:|
|DifferenceKit|||||
|RxDataSources|||||
|IGListKit |||||
|ListDiff |||||
|DeepDiff ||||✅ / ❌ |
|Differ |||||
|Dwifft |||||

#### - Supported section differences
| |Delete|Insert|Move|Reload|
|:------------|:-----|:----:|:--:|:----:|
|DifferenceKit|||||
|:------------|:----:|:----:|:--:|:----:|
|DifferenceKit|||||
|RxDataSources|||||
|IGListKit |||||
|ListDiff |||||
|DeepDiff |||||
|Differ |||||
|Dwifft |||||

### Performance comparison
Performance was measured using `XCTestCase.measure` with `-O -whole-module-optimization`.
Each framework uses a function that can compute as much differences as possible.
Use `Foundation.UUID` as an element.
Use `Foundation.UUID` as an element.

- From 5,000 elements to 500 deleted and 500 inserted
*DeepDiff may had increased the processing speed by misuse of Hashable in algorithm.*

#### - From 5,000 elements to 500 deleted and 500 inserted
| |Time(second)|
|:------------|:-----------|
|DifferenceKit|0.00425 |
|DifferenceKit|0.00425 |
|RxDataSources|0.00784 |
|IGListKit |0.0412 |
|ListDiff |0.0388 |
|Differ |0.449 |
|DeepDiff |0.015 |
|Differ |0.326 |
|Dwifft |33.6 |

- From 10,000 elements to 1,000 deleted and 1,000 inserted

#### - From 10,000 elements to 1,000 deleted and 1,000 inserted
| |Time(second)|
|:------------|:-----------|
|DifferenceKit|0.0079 |
|DifferenceKit|0.0079 |
|RxDataSources|0.0143 |
|IGListKit |0.0891 |
|ListDiff |0.0802 |
|Differ |1.788 |
|DeepDiff |0.030 |
|Differ |1.345 |
|Dwifft ||

- From 100,000 elements to 10,000 deleted and 10,000 inserted

#### - From 100,000 elements to 10,000 deleted and 10,000 inserted
| |Time(second)|
|:------------|:-----------|
|DifferenceKit|0.098 |
|DifferenceKit|0.098 |
|RxDataSources|0.179 |
|IGListKit |1.329 |
|ListDiff |1.026 |
|DeepDiff |0.334 |
|Differ ||
|Dwifft ||

Expand Down Expand Up @@ -278,4 +281,4 @@ If your pull request including new function, please write test cases for it.
---

## License
DifferenceKit is released under the [MIT License](./LICENSE).
DifferenceKit is released under the [MIT License](https://github.com/ra1028/DifferenceKit/blob/master/LICENSE).
File renamed without changes
Loading

0 comments on commit bf77721

Please sign in to comment.