2019独角兽企业重金招聘Python工程师标准>>>
项目中使用到一个开源数据库组件YapDatabase,功能还挺强大的
https://github.com/yapstudios/YapDatabase
YapDatabase
初始化
NSString *databasePath = [self databasePath];
NSLog(@"database path==%@",databasePath);
[[NSFileManager defaultManager] removeItemAtPath:databasePath error:NULL];
// Create the database.
// We do this using the default settings.
// If you want to get fancy, you can do things like customize the serialization/deserialization routines.
DDLogVerbose(@"Creating database instance...");
database = [[YapDatabase alloc] initWithPath:databasePath];
// Create the main view.
// This is a database extension that will sort our objects in the manner in which we want them.
//
// For more information on views, see the wiki article:
// https://github.com/yaptv/YapDatabase/wiki/Views
DDLogVerbose(@"Creating view...");
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withKeyBlock:
^NSString *(YapDatabaseReadTransaction *transaction, NSString *collection, NSString *key)
{
// The grouping block is used to:
// - filter items that we don't want in the view
// - place items into specific groups (which can be used as sections in a tableView, for example)
//
// In this example, we're only storing one kind of object into the database: Person objects.
// And we want to display them all in the same section.
return @"all";
}];
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
^NSComparisonResult(YapDatabaseReadTransaction *transaction, NSString *group,
NSString *collection1, NSString *key1, id object1,
NSString *collection2, NSString *key2, id object2)
{
// The sorting block is used to sort items within their group/section.
__unsafe_unretained Person *person1 = (Person *)object1;
__unsafe_unretained Person *person2 = (Person *)object2;
return [person1.name compare:person2.name options:NSLiteralSearch];
}];
YapDatabaseView *view = [[YapDatabaseView alloc] initWithGrouping:grouping
sorting:sorting
versionTag:@"1"
options:nil];
if (![database registerExtension:view withName:@"order"])
{
DDLogError(@"Unable to register extension: order");
}
插入数据
name.json的数据是这样的一个数组
[
{
"id":39,
"udid":"3cd3f5db-7454-4f81-9efe-06b6cc9e3bf2",
"alive":false,
"name":"Leonor Rios"
},
{
"id":42,
"udid":"b479212b-50e6-43dd-94c7-b5f02e292765",
"alive":false,
"name":"Julia Simmons"
}
]
- (void)asyncPopulateDatabaseIfNeeded
{
[[database newConnection] asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
NSUInteger count = [transaction numberOfKeysInAllCollections];
if (count > 0)
{
// Looks like the database is already populated.
return; // from block
}
DDLogVerbose(@"Loading sample names from JSON file...");
NSString *jsonPath = [[NSBundle mainBundle] pathForResource:@"names" ofType:@"json"];
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:jsonPath];
[inputStream open];
NSArray *people = [NSJSONSerialization JSONObjectWithStream:inputStream options:0 error:nil];
DDLogVerbose(@"Adding sample items to database...");
// Bump the objectCacheLimit for a little performance boost.
// https://github.com/yaptv/YapDatabase/wiki/Performance-Pro
NSUInteger originalObjectCacheLimit = transaction.connection.objectCacheLimit;
transaction.connection.objectCacheLimit = [people count];
[people enumerateObjectsUsingBlock:^(NSDictionary *info, NSUInteger idx, BOOL *stop) {
NSString *name = info[@"name"];
NSString *uuid = info[@"udid"];
Person *person = [[Person alloc] initWithName:name uuid:uuid];
[transaction setObject:person forKey:person.uuid inCollection:@"people"];
}];
transaction.connection.objectCacheLimit = originalObjectCacheLimit;
DDLogVerbose(@"Committing transaction...");
}];
}
YapDatabaseViewGrouping
可以起到过滤的作用,比如某个section中所有的内容
YapDatabaseView
提供子集,分组和排序3个功能,相当于数据库中的where, group by,order by 语句
和coredata中的NSFetchedResultsController 类似
view会随着数据的更新,自动更新对应的内容
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withRowBlock:
^NSString *(YapDatabaseReadTransaction *transaction,
NSString *collection, NSString *key, id object, id metadata)
{
// The parameters to the block come from a row in the database.
// You can inspect the parameters, and determine if the row is included in the view.
// And if so, you can decide which "group" it belongs to.
if ([object isKindOfClass:[BNBook class]])
return @"books";
if ([object isKindOfClass:[BNMagazine class]])
return @"magazines";
return nil; // exclude from view
};
以上的view和下面的字典是比较类似的,相当于对数据,按照key进行了分组和排序
// Conceptualize a view like this NSDictionary:
@{
@"books" : @[ {@"fiction",@"key24"}, {@"fantasy",@"key7"}, {@"mystery",@"key11"} ],
@"magazines" : @[ {@"gossip",@"key60"}, {@"science",@"key49"}, {@"travel",@"key82"} ]
};
完整的YapDatabaseView的初始化
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withRowBlock:
^NSString *(YapDatabaseReadTransaction *transaction,
NSString *collection, NSString *key, id object, id metadata)
{
// The parameters to the block come from a row in the database.
// You can inspect the parameters, and determine if the row is included in the view.
// And if so, you can decide which "group" it belongs to.
if ([object isKindOfClass:[BNBook class]])
return @"books";
if ([object isKindOfClass:[BNMagazine class]])
return @"magazines";
return nil; // exclude from view
};
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
^(YapDatabaseReadTransaction *transaction, NSString *group,
NSString *collection1, NSString *key1, id obj1
NSString *collection2, NSString *key2, id obj2)
{
// The "group" parameter comes from your grouping block.
// The other parameters are from 2 different rows,
// both of which are part of the given "group".
//
// Simply compare the 2 rows however you want,
// and return a NSComparisonResult, just like a compare method.
if ([group isEqualToString:@"books"])
return [obj1 compareBookByTitleThenAuthor:obj2];
else
return [obj1 compareMagazineByMonthThenTitle:obj2];
};
YapDatabaseView *databaseView =
[[YapDatabaseView alloc] initWithGrouping:grouping
sorting:sorting];
注册YapDatabaseView
[database registerExtension:databaseView withName:@"order"];
使用YapDatabaseView
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){
objectForRow = [[transaction ext:@"order"] objectAtIndex:indexPath.row inGroup:@"books"];
}];
和UI同步的技术
Long-Lived Read Transactions
YapDatabaseModifiedNotification
完整的使用demo
- (void)viewDidLoad
{
// Freeze our connection for use on the main-thread.
// This gives us a stable data-source that won't change until we tell it to.
[databaseConnection beginLongLivedReadTransaction];
// The view may have a whole bunch of groups.
// In this example, our view sorts items in a bookstore by selling rank.
// Each book is grouped by its genre within the bookstore.
// We only want to display a subset of genres (not every single genre).
NSArray *groups = @[ @"fantasy", @"sci-fi", @"horror"];
mappings = [[YapDatabaseViewMappings alloc] initWithGroups:groups view:@"salesRank"];
// We can do all kinds of cool stuff with the mappings object.
// For example, we could say we only want to display the top 20 in each genre.
// This will be covered later.
//
// Now initialize the mappings object.
// It will fetch and cache the counts per group/section.
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){
// One-time initialization
[mappings updateWithTransaction:transaction];
}];
// 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 state to an updated state.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:databaseConnection.database];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)sender
{
return [mappings numberOfSections];
}
- (NSInteger)tableView:(UITableView *)sender numberOfRowsInSection:(NSInteger)section
{
return [mappings numberOfItemsInSection:section];
}
- (UITableViewCell *)tableView:(UITableView *)sender cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block Book *book = nil;
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
book = [[transaction extension:@"salesRank"] objectAtIndexPath:indexPath withMappings:mappings];
}];
return [self cellForBook:book];
}
- (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.
// If the UI is a bit backed up, I may jump multiple commits.
NSArray *notifications = [databaseConnection beginLongLivedReadTransaction];
// Process the notification(s),
// and get the change-set(s) as applies to my view and mappings configuration.
NSArray *sectionChanges = nil;
NSArray *rowChanges = nil;
[[databaseConnection ext:@"salesRank"] getSectionChanges:§ionChanges
rowChanges:&rowChanges
forNotifications:notifications
withMappings:mappings];
// No need to update mappings.
// The above method did it automatically.
if ([sectionChanges count] == 0 & [rowChanges count] == 0)
{
// Nothing has changed that affects our tableView
return;
}
// Familiar with NSFetchedResultsController?
// Then this should look pretty familiar
[self.tableView beginUpdates];
for (YapDatabaseViewSectionChange *sectionChange in sectionChanges)
{
switch (sectionChange.type)
{
case YapDatabaseViewChangeDelete :
{
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionChange.index]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case YapDatabaseViewChangeInsert :
{
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionChange.index]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
}
}
for (YapDatabaseViewRowChange *rowChange in rowChanges)
{
switch (rowChange.type)
{
case YapDatabaseViewChangeDelete :
{
[self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case YapDatabaseViewChangeInsert :
{
[self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case YapDatabaseViewChangeMove :
{
[self.tableView deleteRowsAtIndexPaths:@[ rowChange.indexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertRowsAtIndexPaths:@[ rowChange.newIndexPath ]
withRowAnimation:UITableViewRowAnimationAutomatic];
break;
}
case YapDatabaseViewChangeUpdate :
{
[self.tableView reloadRowsAtIndexPaths:@[ rowChange.indexPath ]
withRowAnimation:UITableViewRowAnimationNone];
break;
}
}
}
[self.tableView endUpdates];
}
YapDatabaseMapping
参考资料
https://github.com/yapstudios/YapDatabase/wiki/Views