Skip to content

Automatically drive table view and collection view transitions when data changes.

License

Notifications You must be signed in to change notification settings

stevebrambilla/Changesets

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Changesets Carthage compatible Travis CI

Changesets is a small library used to drive UITableView or UICollectionView transitions when the underlying model changes.

If your table view or collection view's data source is backed by a Collection (eg. Array), Changesets can calculate the inserts, deletes, and updates to transition between states.

Example:

var people: [Person] {
  didSet {
    // Calculate the changeset.
    let changeset = oldValue.changeset(to: people)

    // Start the transition animation - rows are animated using an .automatic row animation by default.
    tableView.performUpdates(changeset: changeset)
  }
}

This is just like the delegate callbacks that a NSFetchedResultsControllerwould emit when using Core Data. With Changesets you get the fine-grained transitions without having to use Core Data.

For example: to transition an array from its original state:

A0 B0 C0 D0 H0 I0

to its new state:

B0 C0 D1 F0 H0 I1 K0

The changeset would report the following changes to perform the transition:

  • Update 'D' at index 3
  • Update 'I' at index 5
  • Delete 'A' at index 0
  • Insert 'F' at index 3
  • Insert 'G' at index 4
  • Insert 'K' at index 7

Changesets takes care of all the nitty-gritty details when updating a table view or collection view. It calculates the diff between the old value and the new value, applies the updates in the correct order, and batches them so they are animated together. All of this in two lines of code:

let changeset = oldValue.changeset(to: newValue)
collectionView.performUpdates(changeset: changeset))

Usage

To calculate the changeset it needs to match the collections' elements to each other. It supports two methods of matching:

Matching with Equatable

Elements that implement Equatable can be matched, with a restriction. When Equatable is used, Changesets can't tell the difference between an object in the collection that has changed and two completely different objects. All it knows is that the two values aren't equal. The Equatable protocol doesn't have any concept of identity.

When an element is only Equatable, we cannot know that A1 is an updated version of A0, so Changesets will report this by doing a delete then insert, rather than an update:

  • Delete A0
  • Insert A1

Matching with Matchable

To use finer-grained changesets you need to take identity into consideration. To do this you can use the Matchable protocol. It's recommended that you implement Matchable for all your types that are used for data sources. Matchable requires one additional function to be implemented for each type:

func match(_ other: Self) -> MatchResult

Where the MatchResult is one of three cases:

public enum MatchResult {
  case sameIdentityEqualValue
  case sameIdentityInequalValue
  case differentIdentity
}

Matchable also provides a default implementation for ==, so implementing the Matchable protocol gives you Equatable for free.

A User struct could be implemented as follows:

struct User: Matchable {
  let userID: Int
  let name: String
  let messageCount: Int

  func match(_ other: User) -> MatchResult {
    guard userID == other.userID else {
      return .differentIdentity
    }

    if name == other.name && messageCount == other.messageCount {
      return .sameIdentityEqualValue
    } else {
      return .sameIdentityInequalValue
    }
  }
}

This way, when the messageCount value changes, Changesets can still recognize that the changed values represent the same user.

Updating UITableViews and UICollectionViews

The first step is to calculate the changeset between the old state of the collection and the new state:

let changeset = oldValue.changeset(to: newValue)

If your data is in a single section you can perform the updates to a UITableView with a single line:

tableView.performUpdates(changeset: changeset)

Or, a UICollectionView:

collectionView.performUpdates(changeset: changeset)

Animations

The default row animation when updating a UITableView is the .automatic row animation. However, the animation can be configured using a custom TableViewChangesetPolicy. The UITableViewRowAnimation values for inserting, deleting, and updating can all be configured.

The animations for UICollectionViews are defined by the collection view layout and are not affected by using changesets.

Sectioned Data

If your data is structured in sections you can split the calculations into two steps:

  1. Calculate the changeset between the sections.
  2. Calculate the changesets between each section's items.

Multiple changesets can be applied by using batch updates. For UITableView:

tableView.beginUpdates()
tableView.applySectionUpdates(changeset: sectionsChangeset) // Insert / delete sections
tableView.applyRowUpdates(changeset: rowChangeset, fromSection: fromSection, toSection: toSection) // One changeset for each section
tableView.endUpdates()

And, for UICollectionView:

collectionView.performBatchUpdates({
  collectionView.applySectionUpdates(changeset: sectionsChangeset) // Insert / delete sections
  collectionView.applyItemUpdates(changeset: itemsChangeset, fromSection: fromSection, toSection: toSection) // One changeset for each section
}, completion: nil)

Installation

If you’re using Carthage, simply add Changesets to your Cartfile:

github "stevebrambilla/Changesets"

Otherwise, you can manually install it by following these steps:

  1. Add the Changesets repository as a submodule of your project's repository.
  2. Drag and drop Changesets.xcodeproj into your Xcode project or workspace.
  3. In the “General” tab of your application target’s settings, add Changesets.framework to the “Embedded Binaries” section.

Now import Changesets and you're all set.

Contact

License

Changesets is available under the MIT license. See the LICENSE file for more information.

About

Automatically drive table view and collection view transitions when data changes.

Resources

License

Stars

Watchers

Forks

Packages

No packages published