I've been developing iPhone apps for the past 9 months using the recommended development tools, being Xcode, Interface Builder and the iPhone SDK.
Being a C# .NET programmer didn't make this easy: Objective-C is... weird and... primitive. Dealing with pointers after 10 years of focusing on problems instead of memory addresses is a slight culture shock, but luckily having previous C and C++ experience helps a lot.
In September last year, the geniuses (by lack of a stronger word) at Novell's Mono team came up with MonoTouch, a C# cross-compiler that allows you to build iPhone apps using .NET and C#, including the use of most of the .NET Framework. I'm not going to go into detail on how this works. Enough has been written about this subject.
One feature of MonoTouch caught my attention: as of version 1.2, an ADO.NET provider was added for accessing the iPhone's native SQLite database format. A relational database accessed from C# code desperately needs an ORM, don't you agree? So last weekend I decided to try and port the CoolStorage ORM to MonoTouch. It wasn't as easy as I thought, because of some severe limitations in the version of SQLite installed on the iPhone, but in the end I got it working, and working well.
To give you an idea of the time you'll save by using an ORM like CoolStorage on the iPhone, I will present three examples:
- Reading a list of records using the iPhones's SQLite library (C / Objective-C)
- Reading a list of records using ADO.NET + MonoTouch
- Reading a list of records using CoolStorage + MonoTouch
We're not going to make it too complicated. The example reads a list of customer records. It retrieves the ID, Name and City. No filters are being applied, simply a list of customers ordered by Name. After that, it prints the records to the console.
The examples also omits the declaration of the Customer class (which is used to hold a single customer record)
Native Objective-C example:
NSArray *documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [documentPaths objectAtIndex:0];
databasePath = [documentsDir stringByAppendingPathComponent:@"mydb.db3"];
sqlite3 *database;
customers = [[NSMutableArray alloc] init];
if(sqlite3_open([databasePath UTF8String], &database) == SQLITE_OK) {
const char *sql = "select id,name,city from customer order by name";
sqlite3_stmt *stmt;
if(sqlite3_prepare_v2(database, sql, -1, &stmt, NULL) == SQLITE_OK) {
while(sqlite3_step(stmt) == SQLITE_ROW) {
Customer *customer = [[Customer alloc] init];
customer.CustomerID = sqlite3_column_int(stmt, 0)];
customer.Name = [NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt, 1)];
customer.City = [NSString stringWithUTF8String:(char *)sqlite3_column_text(stmt, 2)];
[customers addObject:customer];
[customer release];
}
}
sqlite3_finalize(stmt);
}
sqlite3_close(database);
for (int i=0;i<[customers count];i++) {
Customer *customer = [customers objectAtIndex:i];
NSLog("ID: %d, Name: %@, City: %@",customer.CustomerID,customer.Name,customer.City);
}
It's pretty obvious that things will get unbearably complicated when you try to do things like accessing related records, persisting data to the database, and so on.
Now let's introduce MonoTouch and ADO.NET.
ADO.NET example (MonoTouch):
string dbName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "mydb.db3");
var conn = new SqliteConnection("Data Source=" + dbName);
List customers = new List();
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText ="select id,name,city from customer order by name";
using(var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Customer customer = new Customer();
customer.CustomerID = int.Parse(reader["id"].ToString());
customer.Name = (string) reader["name"];
customer.City = (string) reader["city"];
customers.Add(customer);
}
}
}
foreach (var customer in customers)
Console.WriteLine("ID: {0}, Name: {1}, City: {2}",customer.CustomerID,customer.Name,customer.City);
Now that's a lot better, don't you think? But still, it requires a lot of boilerplate code that's just there to distract you from what you're actually trying to do: read a list of records from the database.
So let's move to the next level:
CoolStorage example (MonoTouch):
string dbName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "mydb.db3");
CSConfig.SetDB(dbName, false);
var customers = Customer.List().OrderedBy("Name");
foreach (var customer in customers)
Console.WriteLine("ID: {0}, Name: {1}, City: {2}",customer.CustomerID,customer.Name,customer.City);
Well, you get the picture... Now you can focus on the application instead of data access technology. Isn't this what it's all about?
In case you want to use this in your own code, go ahead and grab the latest development build of CoolStorage, which now fully supports MonoTouch. It can be downloaded from the CoolStorage website. Best of all, it's open source...

•