1. Getting the SPO source
The SPO project page () is the starting point for working with this library. I encourage you to take a look at the Wiki to get an idea of how the library works and what it is capable of. While there is a snapshot available for download, the easiest way to get a copy of the source is to download it via Subversion. Go to the Source tab on the project page for more information on the SPO repository.
Grab a copy of all of the SPO classes and add them to your project. For a clearner project structure, I tend to group these classes together to keep them out of the way.
2. Configure your project
Before we can compile and use the library, we need to add the SQLite framework to our project. SQLite is built in to the SDK, so it's just a matter of referencing it within our project. To do this, right-click on the Frameworks folder in XCode and select Add->Existing Framework. The framework you should be looking for is named libsqlite3.0.dylib.
That's all there is to it. We should now be able to begin our database development using SPO.
3. Setup your database
SPO will need to locate a database that is part of your project. It will not create an empty one for you. Luckily, creating a database is very simple if you have installed XCode correctly. Simply open a terminal window and type:
sqlite3
This will create the new database in your current working directory. To add this file to your project, simply drag and drop it into the Resources folder within your project.
Whether you're working with SPO or not, you need to make sure that the database is properly setup and accessed at the runtime of your application. Apple's SQLiteBooks example gives boilerplate code that you can copy and paste right into your AppDelegate class. This code will determine if a database exists for the application and, if not, create one for you by copying the default database out of your Resources folder. We have made a couple of small changes to ensure that SPO is also notified of your database location. Simply paste the following code into your AppDelegate class to get started:
- (void)createEditableCopyOfDatabaseIfNeeded {
// First, test for existence.
BOOL success;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *writableDBPath = [documentsDirectory stringByAppendingPathComponent:@".sqlite"];
success = [fileManager fileExistsAtPath:writableDBPath];
if (success) {
[[SQLiteInstanceManager sharedManager] setDatabaseFilepath:writeableDBPath];
return;
}
// The writable database does not exist, so copy the default to the appropriate location.
NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@".sqlite"];
success = [fileManager copyItemAtPath:defaultDBPath toPath:writableDBPath error:&error];
if (!success) {
NSAssert1(0, @"Failed to create writable database file with message '%@'.", [error localizedDescription]);
}
[[SQLiteInstanceManager sharedManager] setDatabaseFilepath:writeableDBPath];
}
Make sure you replace "
[self createEditableCopyOfDatabaseIfNeeded];
SPO and your database are now ready for business.
4. Create your data object
With our database setup out of the way, we can now begin working with SPO. We will create a couple of simple data model classes to demonstrate how SPO provides object persistence. If you choose to implement this code in your project, make sure you define your @property statements correctly. We have omitted them for sake of time. Our data model interfaces look like this:
@interface PersonModel : SQLitePersistentObject {
NSString *name;
NSString *nickname;
NSDate *dateOfBirth;
AddressModel *address;
}
@interface AddressModel : SQLitePersistentObject {
NSString *street;
NSString *city;
NSString *state;
NSString *zipCode;
}
You'll notice that all we had to do to SPO-enable our data model classes was to extend SQLitePersistentObject. This will take care of the primary key, as well as provide all of the helper methods we will make use of later on.
Now that our models are setup, we want to save an entry to our database. We can create our PersonModel object like this:
PersonModel *p = [[PersonModel alloc] init];
p.name = @"Joe Blow";
p.nickName = ...
p.date = ...
AddressModel *a = [[AddressModel alloc] init];
a.street = @"123 Main St."
...
p.address = a;
To save the PersonModel object to the database, all we need to do is call:
[p save];
That's it. No need to worry about opening a connection or any other SQL statements necessary. Our AddressModel object that is associated with the PersonModel object will also be saved with this call. There is no need to save it with a separate call. To load all of the PersonModel objects stored in the database, we simply call:
NSArray *people = [[PersonModel class] allObjects];
This will return an NSArray containing all of the PersonModel objects and their associated AddressModel objects.
Conclusion
As you've seen, SQLite PersistentObjects makes SQLite development on the iPhone much quicker. Stay tuned for Part 2, where we'll investigate some more advanced functionality that SPO provides, including queries and indices.
I've just found the command:
ReplyDeletesqlite3 .sqlite
didnt generate the db.
I had to do:
sqlite3 mydatabase
create table test( one varchar(10), two smallint );
.quit
Then the database was created.
Great stuff! You have one typo in the provided setup code though:
ReplyDeleteTwice you reference a variable called writeableDBPath when in fact it should be writableDBPath. (difference is the 'e')