YapDatabase的使用

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

项目中使用到一个开源数据库组件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

 

转载于:https://my.oschina.net/u/2360054/blog/720038

你可能感兴趣的:(YapDatabase的使用)