diff --git a/Changeset.xcodeproj/project.pbxproj b/Changeset.xcodeproj/project.pbxproj index 9fa0f75..e3aa6db 100644 --- a/Changeset.xcodeproj/project.pbxproj +++ b/Changeset.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 29078AC81C895E9F00FBBEC9 /* DataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29078AC71C895E9F00FBBEC9 /* DataSource.swift */; }; + 29214F661DE4DF9D000677A7 /* UIKit+Changeset.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC41787B1C6EF39100296FD8 /* UIKit+Changeset.swift */; }; 29828DD41C2A899E0056284E /* Changeset.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29828DC91C2A899D0056284E /* Changeset.framework */; }; 29828DD91C2A899E0056284E /* ChangesetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29828DD81C2A899E0056284E /* ChangesetTests.swift */; }; 29828DE41C2A8BD40056284E /* Changeset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29828DE31C2A8BD40056284E /* Changeset.swift */; }; @@ -17,7 +18,6 @@ CC41786F1C6EE5E000296FD8 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CC41786E1C6EE5E000296FD8 /* Assets.xcassets */; }; CC4178721C6EE5E000296FD8 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CC4178701C6EE5E000296FD8 /* LaunchScreen.storyboard */; }; CC41787A1C6EE8C700296FD8 /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4178791C6EE8C700296FD8 /* CollectionViewCell.swift */; }; - CC41787C1C6EF39100296FD8 /* UIKit+Changeset.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC41787B1C6EF39100296FD8 /* UIKit+Changeset.swift */; }; CC41787E1C6EF41000296FD8 /* Changeset.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 29828DC91C2A899D0056284E /* Changeset.framework */; }; CC41787F1C6EF41000296FD8 /* Changeset.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 29828DC91C2A899D0056284E /* Changeset.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CC4178841C6EF88B00296FD8 /* Changeset+Naive.swift in Sources */ = {isa = PBXBuildFile; fileRef = CC4178831C6EF88B00296FD8 /* Changeset+Naive.swift */; }; @@ -134,6 +134,7 @@ isa = PBXGroup; children = ( 29828DE31C2A8BD40056284E /* Changeset.swift */, + CC41787B1C6EF39100296FD8 /* UIKit+Changeset.swift */, 29828DCE1C2A899D0056284E /* Info.plist */, ); path = Sources; @@ -175,7 +176,6 @@ CC3454A91C854BEF00CE0C4D /* TableViewController.swift */, CCDD53611C7D901F00FEBCFC /* CollectionViewController.swift */, CC4178791C6EE8C700296FD8 /* CollectionViewCell.swift */, - CC41787B1C6EF39100296FD8 /* UIKit+Changeset.swift */, CC4178831C6EF88B00296FD8 /* Changeset+Naive.swift */, 29078AC71C895E9F00FBBEC9 /* DataSource.swift */, CC41786E1C6EE5E000296FD8 /* Assets.xcassets */, @@ -330,6 +330,7 @@ buildActionMask = 2147483647; files = ( 29828DE41C2A8BD40056284E /* Changeset.swift in Sources */, + 29214F661DE4DF9D000677A7 /* UIKit+Changeset.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -348,7 +349,6 @@ CC4178841C6EF88B00296FD8 /* Changeset+Naive.swift in Sources */, CC3454AA1C854BEF00CE0C4D /* TableViewController.swift in Sources */, CC4178681C6EE5E000296FD8 /* AppDelegate.swift in Sources */, - CC41787C1C6EF39100296FD8 /* UIKit+Changeset.swift in Sources */, CC41787A1C6EE8C700296FD8 /* CollectionViewCell.swift in Sources */, CCDD53621C7D901F00FEBCFC /* CollectionViewController.swift in Sources */, 29078AC81C895E9F00FBBEC9 /* DataSource.swift in Sources */, diff --git a/README.md b/README.md index 42cfbf9..5168405 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,7 @@ let edits = [ assert(changeset.edits == edits) ``` -These index values can be used directly in the animation blocks of `beginUpdates`/`endUpdates` on `UITableView` and `performBatchUpdates` on `UICollectionView` in that `Changeset` follows the principles explained under [_Batch Insertion, Deletion, and Reloading of Rows and Sections_](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html#//apple_ref/doc/uid/TP40007451-CH10-SW9) in Apple’s [Table View Programming Guide for iOS](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/AboutTableViewsiPhone/AboutTableViewsiPhone.html). - -In short; first all deletions and substitutions are made, relative to the source collection, then, relative to the resulting collection, insertions. A move is just a deletion followed by an insertion. - -If you don’t want the overhead of `Changeset` itself, which also stores the source and target collections, you can call `edits` directly (here with [example data](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html#//apple_ref/doc/uid/TP40007451-CH10-SW16) from Apple’s guide): +If you don’t want the overhead of `Changeset` itself, which also stores the source and target collections, you can call `edits` directly (here with [example data](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html#//apple_ref/doc/uid/TP40007451-CH10-SW16) from Apple’s [Table View Programming Guide for iOS](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/AboutTableViewsiPhone/AboutTableViewsiPhone.html)): ```swift let source = ["Arizona", "California", "Delaware", "New Jersey", "Washington"] @@ -48,14 +44,26 @@ let edits = Changeset.edits(from: source, to: target) print(edits) // [insert Alaska at index 0, replace with Georgia at index 2, replace with Virginia at index 4] ``` + +## UIKit Integration + +The index values can be used directly in the animation blocks of `beginUpdates`/`endUpdates` on `UITableView` and `performBatchUpdates` on `UICollectionView` in that `Changeset` follows the principles explained under [_Batch Insertion, Deletion, and Reloading of Rows and Sections_](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html#//apple_ref/doc/uid/TP40007451-CH10-SW9) in Apple’s guide. + +In short; first all deletions and substitutions are made, relative to the source collection, then, relative to the resulting collection, insertions. A move is just a deletion followed by an insertion. + +In the iOS framework, two convenience extensions (one on `UITableView` and one on `UICollectionView`) have been included to make animated table/collection view updates a breeze. Just call `update`, like this: + +```swift +tableView.update(with: changeset.edits) +``` ## Test App -The Xcode project contains a target to illustrate the usage in an app: +The Xcode project also contains a target to illustrate the usage in an app: -![Test App](Test\ App/Screen.png "Test App") +![Test App](Test\ App/Screen.gif "Test App") -This includes simple extensions on `UITableview` and `UICollectionView` making it trivial to animate transitions based on the edits of a `Changeset`. +This uses the extensions mentioned above to animate transitions based on the edits of a `Changeset`. ## License diff --git a/Test App/UIKit+Changeset.swift b/Sources/UIKit+Changeset.swift similarity index 75% rename from Test App/UIKit+Changeset.swift rename to Sources/UIKit+Changeset.swift index 596764e..f9f3073 100644 --- a/Test App/UIKit+Changeset.swift +++ b/Sources/UIKit+Changeset.swift @@ -1,19 +1,20 @@ // // UIKit+Changeset.swift -// Changeset +// Copyright (c) 2016 Joachim Bondo. All rights reserved. // +#if os(iOS) + import UIKit -import Changeset extension UITableView { /// Performs batch updates on the table view, given the edits of a Changeset, and animates the transition. - public func updateWithEdits (_ edits: [Edit], inSection section: Int) { + open func update(with edits: [Edit], in section: Int = 0) { guard !edits.isEmpty else { return } - let indexPaths = batchIndexPathsFromEdits(edits, inSection: section) + let indexPaths = batchIndexPaths(from: edits, in: section) self.beginUpdates() if !indexPaths.deletions.isEmpty { self.deleteRows(at: indexPaths.deletions, with: .automatic) } @@ -26,11 +27,11 @@ extension UITableView { extension UICollectionView { /// Performs batch updates on the table view, given the edits of a Changeset, and animates the transition. - public func updateWithEdits (_ edits: [Edit], inSection section: Int, completion: ((Bool) -> Void)? = nil) { + open func update(with edits: [Edit], in section: Int = 0, completion: ((Bool) -> Void)? = nil) { guard !edits.isEmpty else { return } - let indexPaths = batchIndexPathsFromEdits(edits, inSection: section) + let indexPaths = batchIndexPaths(from: edits, in: section) self.performBatchUpdates({ if !indexPaths.deletions.isEmpty { self.deleteItems(at: indexPaths.deletions) } @@ -40,7 +41,7 @@ extension UICollectionView { } } -private func batchIndexPathsFromEdits (_ edits: [Edit], inSection section: Int) -> (insertions: [IndexPath], deletions: [IndexPath], updates: [IndexPath]) { +private func batchIndexPaths (from edits: [Edit], in section: Int) -> (insertions: [IndexPath], deletions: [IndexPath], updates: [IndexPath]) { var insertions = [IndexPath]() var deletions = [IndexPath]() @@ -64,3 +65,5 @@ private func batchIndexPathsFromEdits (_ edits: [Edit], inSecti return (insertions: insertions, deletions: deletions, updates: updates) } + +#endif diff --git a/Test App/CollectionViewController.swift b/Test App/CollectionViewController.swift index 51a7d24..f684015 100644 --- a/Test App/CollectionViewController.swift +++ b/Test App/CollectionViewController.swift @@ -13,7 +13,7 @@ class CollectionViewController: UICollectionViewController { @IBAction func test(_ sender: UIBarButtonItem) { self.dataSource.runTests() { (edits: [Edit], isComplete: Bool) in - self.collectionView?.updateWithEdits(edits, inSection: 0) + self.collectionView?.update(with: edits) sender.isEnabled = isComplete } } diff --git a/Test App/Screen.gif b/Test App/Screen.gif new file mode 100644 index 0000000..40d60ca Binary files /dev/null and b/Test App/Screen.gif differ diff --git a/Test App/Screen.png b/Test App/Screen.png deleted file mode 100644 index 9582aa1..0000000 Binary files a/Test App/Screen.png and /dev/null differ diff --git a/Test App/TableViewController.swift b/Test App/TableViewController.swift index 65bc4ab..0188ee5 100644 --- a/Test App/TableViewController.swift +++ b/Test App/TableViewController.swift @@ -13,7 +13,7 @@ class TableViewController: UITableViewController { @IBAction func test(_ sender: UIBarButtonItem) { self.dataSource.runTests() { (edits: [Edit], isComplete: Bool) in - self.tableView.updateWithEdits(edits, inSection: 0) + self.tableView.update(with: edits) sender.isEnabled = isComplete } }