-
Notifications
You must be signed in to change notification settings - Fork 365
YapDatabaseModifiedNotification
Answering that age old question: "What's new?"
YapDatabase simplifies many aspects of database development. It provides a simple Objective-C API. It has a straight-forward concurrency model that is a pleasure to use. And it provides a number of other great features such as built-in caching.
But sometimes the database itself isn't the difficult aspect of development. Sometimes it's updating the UI and keeping it in-sync with the underlying data model.
There are 2 features that make it dead simple to keep the User Interface in-sync with the data layer.
- Long-Lived Read Transactions
- YapDatabaseModifiedNotification
The first feature is long-lived read transactions. There is a dedicated wiki article for this topic. The rest of this article assumes you've already read the LongLivedReadTransactions article.
The second feature is the YapDatabaseModifiedNotification. These notifications allow you to figure out what changed during any particular read-write transaction.
- (void)viewDidLoad
{
// Freeze my database connection while I draw my views and populate my tableView.
// Background operations are free to update the database using their own connection.
[databaseConnection beginLongLivedReadTransaction];
// Register for notifications of changes to the database.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:database];
}
- (void)yapDatabaseModified:(NSNotification *)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.
NSArray *notifications = [database beginLongLivedReadTransaction];
// Update views if needed
if ([databaseConnection hasChangeForKey:itemId inNotifications:notifications]) {
[self updateItemView];
}
// ...
}As you can see, these 2 features allow you to write code in a natural manner on the main thread. Even though you have all the power and concurrency of YapDatabase throughout the rest of your app, you can easily provide a stable database connection for the main thread. And you can easily manage moving your UI from one state to another.
YapDatabase comes with several cool extensions. One such extension is Views, which allows you to do some pretty cool stuff. Views are particularly helpful when displaying your data in a tableView or collectionView.
And extensions are also integrated into the YapDatabaseModifiedNotification architecture.
If a picture is worth a thousand words, what's the ratio for code?
- (NSInteger)tableView:(UITableView *)sender numberOfRowsInSection:(NSInteger)section
{
__block NSUInteger count = 0;
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
count = [[transaction extension:@"sales"] numberOfKeysInGroup:@"bestSellers"];
}];
return (NSInteger)count;
}
- (UITableViewCell *)tableView:(UITableView *)sender cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block SaleItem *item = nil;
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
item = [[transaction extension:@"sales"] objectAtIndex:indexPath.row inGroup:@"bestSellers"];
}];
return [self cellForItem:item];
}
- (void)yapDatabaseModified:(NSNotification *)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.
NSArray *notifications = [databaseConnection beginLongLivedReadTransaction];
// What changed in my tableView?
NSDictionary *mappings = @{ @"bestSellers" : @(0) };
NSArray *changes = [[databaseConnection extension:@"sales"] changesForNotifications:notifications
withGroupToSectionMappings:mappings];
if ([changes count] == 0)
{
// There aren't any changes that affect our tableView!
return;
}
// Familiar with NSFetchedResultsController?
// Then this should look pretty familiar
[self.tableView beginUpdates];
for (YapDatabaseViewChange *change in changes)
{
switch (change.type)
{
case YapDatabaseViewChangeDelete :
{
[self.tableView deleteRowsAtIndexPaths:@[ change.indexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case YapDatabaseViewChangeInsert :
{
[self.tableView insertRowsAtIndexPaths:@[ change.newIndexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case YapDatabaseViewChangeMove :
{
[self.tableView deleteRowsAtIndexPaths:@[ change.indexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertRowsAtIndexPaths:@[ change.newIndexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case YapDatabaseViewChangeUpdate :
{
[self.tableView reloadRowsAtIndexPaths:@[ change.indexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
}
}
[self.tableView endUpdates];
}