Skip to content

Commit

Permalink
readme!
Browse files Browse the repository at this point in the history
  • Loading branch information
jflinter committed Apr 14, 2017
1 parent 5f24948 commit e536f0f
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 12 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Dwifft is meant to be as small as possible. If you want to increase the API surface area, you should have a damn good reason, so please open an issue to talk about it first so that you don't waste your time making a PR that gets closed. The same goes if you want to modify the architecture or overall code structure. In general, I am considerably faster at replying to issues than PRs so if you are contemplating a change, it's never a bad idea to open one and talk about it first before committing more time to it. Thanks for reading, and thanks in advance for your help!
38 changes: 26 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,40 @@
Dwifft!
===

OK. Dwifft is a Swift library that does two things. The first thing sounds interesting but perhaps only abstractly useful, and the other thing is a very concretely useful thing based off the first thing.

The first thing (found in `Dwifft.swift`) is an algorithm that solves the [Longest Common Subsequence problem](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem). Pragmatically, the problem of finding the difference between two arrays is trivially reducable to the LCS problem, i.e. if you can find the longest common subsequence between two arrays, you've also found a series of transforms to apply to array 1 that will result in array 2. This algorithm is written purely in Swift, and uses dynamic programming to achieve substantial performance improvements over a naïve approach (that being said, there are several ways it could probably be sped up.) Perhaps by now you've figured out that Dwifft is a terrible/brilliant portmanteau of "Swift" and "Diff". If this kind of thing is interesting to you, there's a pretty great paper on diffing algorithms: http://www.xmailserver.org/diff2.pdf
In 10 seconds
---
Dwifft is a small Swift library that tells you what the "diff" is between two collections, namely, the series of "edit operations" required to turn one into the other. It also comes with UIKit bindings, to automatically, animatedly keep a UITableView/UICollectionView in sync with a piece of data by making the necessary row/section insertion/deletion calls for you as the data changes.

The second thing (found in `Dwifft+UIKit.swift`) is a series of diff calculators for `UITableView`s and `UICollectionView`s. Let's say you have a `UITableView` that's backed by a simple array of values (like a list of names, e.g. `["Alice", "Bob", "Carol"]`. If that array changes (maybe Bob leaves, and is replaced by Dave, so our list is now `["Alice, "Carol", "Dave"]`), we'll want to update the table. The easiest way to do this is by calling `reloadData` on it. This has a couple of downsides: the transition isn't animated, and it'll cause your user to lose their scroll position if they've scrolled the table. The nicer way is to use the `insertRowsAtIndexPaths:withRowAnimation` and `deleteRowsAtIndexPaths:withRowAnimation` methods on `UITableView`, but this requires you to figure out which index paths have changed in your array (in our example, you'd have to figure out that the row at index 1 should be removed, and a new row should be inserted at index 2 should then be added). If only we had a way to diff the previous value of our array with it's new value. Wait a minute.
Longer version
---
Dwifft is a Swift library that does two things. The first thing sounds interesting but perhaps only abstractly useful, and the other thing is a very concretely useful thing based off the first thing.

When you wire up a `TableViewDiffCalculator` to your `UITableView` (or a `CollectionViewDiffCalculator` to your `UICollectionView`, it'll _automatically_ calculate diffs and trigger the necessary animations on it whenever you change its `rows` property. Neat, right? Usually, this `rows` object will be the same thing you're using in your `UITableViewDataSource` methods. The only constraint is that the items in that `rows` array have to conform to `Equatable`, because, you know, how else could you compare them?
The first thing (found in `Dwifft.swift`) is an algorithm that calculates the diff between two collections using the [Longest Common Subsequence method](https://en.wikipedia.org/wiki/Longest_common_subsequence_problem). If this kind of thing is interesting to you, there's a pretty great paper on diffing algorithms: http://www.xmailserver.org/diff2.pdf

This makes slightly more sense in code, so check out the tests (which show `LCS`/`Diff` in action) and the example app (which demonstrates the use of `TableViewDiffCalculator`). You can quickly run the example with `pod try Dwifft`.
The second thing (found in `Dwifft+UIKit.swift`) is a series of diff calculators for `UITableView`s and `UICollectionView`s. Let's say you have a `UITableView` that's backed by a simple array of values (like a list of names, e.g. `["Alice", "Bob", "Carol"]`. If that array changes (maybe Bob leaves, and is replaced by Dave, so our list is now `["Alice, "Carol", "Dave"]`), we'll want to update the table. The easiest way to do this is by calling `reloadData` on it. This has a couple of downsides: the transition isn't animated, and it'll cause your user to lose their scroll position if they've scrolled the table. The nicer way is to use the `insertRowsAtIndexPaths:withRowAnimation` and `deleteRowsAtIndexPaths:withRowAnimation` methods on `UITableView`, but this requires you to figure out which index paths have changed in your array (in our example, you'd have to figure out that the row at index 1 should be removed, and a new row should be inserted at index 2 should then be added). If only we had a way to diff the previous value of our array with it's new value. Wait a minute.

Thanks for reading! PRs and such are of course welcome, but I want to keep this pretty tightly-scoped, so I'd politely request you open an issue before going off and implementing any new functionality so we can talk things over first.
When you wire up a `TableViewDiffCalculator` to your `UITableView` (or a `CollectionViewDiffCalculator` to your `UICollectionView`, it'll _automatically_ calculate diffs and trigger the necessary animations on it whenever you change its `sectionedValues` property. Neat, right? Notably, as of Dwifft 0.6, Dwifft will also figure out _section_ insertions and deletions, as well as how to efficiently insert and delete rows across different sections, which is just so massively useful if you have a multi-section table. If you're currently using a <0.6 version of Dwifft and want to do this, read the [0.6 release notes](TODO).

Happy dwiffing!
Even longer version
---
Learn more about the history of Dwifft, and how it works, in this [exciting video of a talk](https://vimeo.com/211194798) recorded at the Brooklyn Swift meetup in March 2017.

Oh right, how to install
Why you should use Dwifft
---
- Dwifft is *useful* - it can help you build a substantially better user experience if you have table/collection views with dynamic content in your app.
- Dwifft is *safe* - there is some non-trivial index math inside of this diff algorithm that is easy to screw up. Dwifft has 100% test coverage on all of its core algorithms. Additionally, all of Dwifft's core functionality is tested with [SwiftCheck](https://github.com/typelift/SwiftCheck), meaning it has been shown to behave correctly under an exhausting set of inputs and edge cases.
- Dwifft is *fast* - a lot of time has been spent making Dwifft considerably (many orders of magnitude) faster than a naïve implementation. It almost certainly won't be the bottleneck in your UI code.
- Dwifft is *small* - Dwifft believes (to the extent that a software library can "believe" in things) in the unix philosophy of small, easily-composed tools. It's unopinionated and flexible enough to fit into most apps, and leaves a lot of control in your hands as a developer. As such, you can probably cram it into your app in less than 5 minutes. Also, because it's small, it can actually achieve nice goals like 100% test and documentation coverage.

Cocoapods or Carthage. You'll need to use cocoapods frameworks because Swift. Version 0.1 is written in Swift 1.2, versions 0.2-0.3.1 are Swift 2, beyond that is Swift 3.
How to get started
---
- First, you should take a look at the example app, to get a feel for how Dwifft is meant to be used.
- Next, you should just sit down and read the [entire documentation](TODO) - it will take you <10 minutes, and you'll leave knowing everything there is to know about Dwifft.
- Then, install Dwifft via cocoapods or carthage or whatever people are using these days.
- Then get to Dwiffing.

A fun gif
Contributing
---
Contributions are welcome, with some caveats - please read the [contributing guidelines](TODO) before opening a PR to avoid wasting both our time.

<img src="dwifft.gif" alt="Dwifft" style="width: 375px !important;"/>
Ok, that's it, there's nothing more here.

0 comments on commit e536f0f

Please sign in to comment.