-
Notifications
You must be signed in to change notification settings - Fork 363
ViewAnimations
Robbie Hanson edited this page Nov 11, 2019
·
1 revision
I can animate that.
The primary use case for Views is to be the data-source for a tableView or collectionView. And there are tools that make it easy to animate changes to your tableView or collectionView when the underlying YapDatabaseView changes.
- You should understand LongLivedReadTransactions
- You should understand YapDatabaseModifiedNotification
- You should understand the basics of Views
- You should understand ViewMappings
override func viewDidLoad() {
// ...
// Freeze our databaseConnection on the current commit.
// This gives us a snapshot-in-time of the database,
// and thus a stable data source for our UI thread.
dbConnection.beginLongLivedReadTransaction()
// Initialize our mappings.
// Note that we do this AFTER we've started our database longLived transaction.
initializeMappings()
// And register for notifications when the database changes.
// Our method will be invoked on the main-thread,
// and will allow us to move our stable data-source from
// our existing commit to an updated commit.
let nc = NotificationCenter.default
nc.addObserver( self,
selector: #selector(self.yapDatabaseModified(notification:)),
name: Notification.Name.YapDatabaseModified,
object: nil)
}
func initializeMappings() {
dbConnection.read {(transaction) in
guard
let _ = transaction.ext("SalesRank") as? YapDatabaseViewTransaction
else {
// The underlying View isn't ready yet.
// Delay creating mappings until it's ready.
return
}
// The view may have a whole bunch of groups.
// In this example, we just want to look at a single group (1 section).
let groups = ["fantasy", "sci-fi", "horror"]
mappings = YapDatabaseViewMappings(groups:groups, view:"SalesRank")
// One-time initialization
mappings?.update(with: transaction)
}
}
func numberOfSections(in tableView: UITableView) -> Int {
if let mappings = self.mappings {
return Int(mappings.numberOfSections())
} else {
return 0
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if let mappings = self.mappings {
return Int(mappings.numberOfItems(inSection: UInt(section)))
} else {
return 0
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var obj: Any? = nil
dbConnection.read {(transaction) in
if let viewTransaction = transaction.ext("SalesRank") as? YapDatabaseViewTransaction,
let mappings = self.mappings
{
obj = viewTransaction.object(at: indexPath, with: mappings)
}
}
// configure and return cell...
}
@objc func yapDatabaseModified(notification: Notification) {
// Jump to the most recent commit.
// End & Re-Begin the long-lived transaction atomically.
// Also grab all the notifications for all the commits that I jump.
// If the UI is a bit backed up, I may jump multiple commits.
let notifications = dbConnection.beginLongLivedReadTransaction()
guard let mappings = self.mappings {
initializeMappings()
self.tableView.reloadData()
return
}
guard let ext = dbConnection.ext("SalesRank") as? YapDatabaseViewConnection else {
return
}
// Process the notification(s),
// and get the change-set(s),
// as applies to my view and mappings configuration.
let (sectionChanges, rowChanges) = ext.getChanges(forNotifications: notifications, withMappings: mappings)
if (sectionChanges.count == 0) && (rowChanges.count == 0) {
// There aren't any changes that affect our tableView!
return
}
// Animate tableView updates !
tableView.beginUpdates()
for change in sectionChanges {
switch change.type {
case .delete:
tableView.deleteSections(IndexSet(integer: Int(change.index)), with: .automatic)
case .insert:
tableView.insertSections(IndexSet(integer: Int(change.index)), with: .automatic)
default: break
}
}
for change in rowChanges {
switch change.type {
case .delete:
tableView.deleteRows(at: [change.indexPath!], with: .automatic)
case .insert:
tableView.insertRows(at: [change.newIndexPath!], with: .automatic)
case .move:
tableView.moveRow(at: change.indexPath!, to: change.newIndexPath!)
case .update:
tableView.reloadRows(at: [change.indexPath!], with: .automatic)
default: break
}
}
tableView.endUpdates()
}