For some reason, SQL databases always felt strange to me.
You try to create a optimal object-oriented structure, use attributes on objects to set and get data. And when you’re using less object-structured data like dictionaries, you use the (almost same) key-value coding as you do with dictionaries.
And then you have to store things… Using traditional relational databases, the next step is to create a ORM (object-relational mapper) to map those beautiful dynamic lists of objects into a table. A completely different approach of data representation: a two dimensional structure with tables, columns and rows.
NoSQL
Thank god for document and key-value stores like MongoDB and Redis! With the right tools, they enable you to create, store, change and extend your objects without thinking about database migrations.
Using such storage on you server side, makes you frustrated you have to revert to SQL for storage on the iPhone. Especially when you simply want to embed objects into other objects.
Countries with cities
For instance: you want to create multiple “Country” objects, which stores a ordered list of “City” objects (by alphabet). Perfectly fine in the object-oriented mind of a Objective-C programmer. But if you want to store these objects, and you want to retrieve a country with its cities. You’re out of luck…
First you have to retrieve the city you want to fetch, by name for instance, and you have to fetch all cities with a specific “city_id” matching the identifier of the city. Finishing the task by putting the list of city objects in the “cities” attribute of the country object.
Could be simpler right? SQL brings a lot of power when it comes to filtering and searching through your data. In this case, and many cases: SQL brings more pain then joy.
BNRPersistence
So let’s bring some noSQL goodness onto the iPhone by using BNRPersistence. BNRPersistence is a Objective-C wrapper for the key-value store “Tokyo Cabinet”.
With large data sets, BNRPersistence can be 10 to 17 times faster then the traditional CoreData. While sacrificing complex searching and filtering, you get a new storage layer which is not only faster but also much simpler!
Once you get past the (bit more difficult) installation, adding the storage functionality is more then easy. Start off by extending the BNRStoredObject class in your object.
#import "BNRStoredObject.h"
@class City;
@interface Country : BNRStoredObject {
NSString *name;
NSMutableArray *cities;
}
- (void)setName:(NSString *)n;
- (NSString *)name;
- (NSArray *)cities;
@end
Next step is to add the data serialization and deserialization functions to your class, like this:
- (void)readContentFromBuffer:(BNRDataBuffer *)d
{
[name release];
name = [[d readString] retain];
[cities release];
cities = [d readArrayOfClass:[City class] usingStore:[self store]];
[cities retain];
}
- (void)writeContentToBuffer:(BNRDataBuffer *)d
{
[d writeString:name];
[d writeArray:cities ofClass:[city class]];
}
And your up and running! For other functions you can use, just check the header file of BNRStoredObject.
At the moment, BNRPersistence shows some immaturity… So you can walk into some drawbacks:
- The framework isn’t thread safe currently, so lock your stuff or use one thread for storing data.
- Stored data can be quite a bit larger then when using CoreData, so think things through what you want to store and what not.
- Next to full-text searching, you don’t have a lot of other added functionalities. If you need things from CoreData, just use them side by side.
All in all, if you are frustrated by the cumbersome managed object contexts and managed objects or looking a fast and simple storage method (with built in versioning). Definitely give BNRPersistence a try!