Hello World

Robbie Hanson edited this page Aug 14, 2014 · 7 revisions

"Hello World", YapDatabase style:

// Create and/or Open the database file
YapDatabase *database = [[YapDatabase alloc] initWithPath:databasePath];

// Get a connection to the database (can have multiple for concurrency)
YapDatabaseConnection *connection = [database newConnection];

// Add an object
[connection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
    [transaction setObject:@"Hello" forKey:@"World" inCollection:@"example1"];
}];

// Read it back
[connection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
    NSLog(@"%@ World", [transaction objectForKey:@"World" inCollection:@"example1"]);
}];

One way to think of YapDatabase is as a "dictionary of dictionaries". Except the values get stored to disk.

As you might guess, you can do a whole bunch of stuff within a single transaction block. For example, you can do batch inserts, or enumerate all objects in the database.

Concurrency

A transaction represents a single atomic operation to the database. Furthermore a read-only transaction represents an immutable snapshot-in-time of the database. Even if another connection makes changes to the data, those changes don't affect an in-progress read-only transaction. Thus your data stays in a consistent state.

Concurrency is straight-forward. Here are the rules:

  • You can have multiple connections.
  • Every connection is thread-safe.
  • You can have multiple read-only transactions simultaneously without blocking.
  • You can have multiple read-only transactions and a single read-write transaction simultaneously without blocking.
  • There can only be a single read-write transaction at a time. Read-write transactions go through a per-database serial queue.
  • There can only be a single transaction per connection at a time. Transactions go through a per-connection serial queue.

Here's how simple it is to add concurrency:

- (void)viewDidLoad
{
    connection = [database newConnection]; // For main thread (e.g. cellForIndexPath)
    backgroundConnection = [database newConnection]; // Spice it up with concurrency
}

- (void)dataDidDownload:(NSArray *)objects
{
    // Perform updates on background thread.
    // The 'backgroundConnection' won't block the separate 'connection',
    // so the user can continue scrolling as fast as possible.
    // Furthermore the 'asyncTransaction' makes it dead-simple for us.

    [backgroundConnection asyncReadWriteWithTransaction:^(YapDatabaseReadWriteTransaction *transaction) {

        for (id object in objects) {
            [transaction setObject:object forKey:object.key inCollection:@"sprockets"];
        }

    } completionBlock:^{

        // Back on the main thread, let's update our view
        [self newDataAvailable];
    }];
}

Plugins

A key/value database by itself may be nice, but it might not provide all the functionality you need as an application developer. And that's where extensions come in.

The key/value architecture of YapDatabase is just the foundation for an advanced plugin system. These plugins are called "extensions". And they integrate rather seamlessly.

As an example, do you need to display your data in a tableView? Perhaps a subset of it, sorted a certain way, and maybe grouped a certain way too. No problem. A YapDatabaseView is an extension designed to do just that. And it gives you NSFetchedResultsController style updates, so animating changes in your tableView/collectionView is a breeze.

Or maybe you need to run queries against the database to find items. No problem. The secondary index extension can help you setup indexes on the properties you want, and can even handle SQL style queries.

Full text search? Gotcha covered. There's an extension built atop the FTS module written by Google.

Every app is different. In fact apps themselves change from version to version, along with the requirements they place on their database. And herein lies the beauty of extensions. They can be swapped in and out whenever you need. Perhaps you didn't need secondary indexes in version 1, but then version 2 comes along. No problem. The database system can set it up for you with just a few lines of code. In fact, extensions can be swapped in and out while the app is running, and while you're using the database. And you get all of this without worrying about making any changes to your objects, or how you store them.

Now that you've got the idea, learn more about YapDatabase by checking out the other wiki articles.