Professional Documents
Culture Documents
iOS
The iOS SDK has many data persistent solutions, including SQLite, Core Data, archiving, property
lists and files to name a few. Prior to Core Data, SQLite was the de facto standard for data
persistence on an iOS device. The database continues to be a favorite solution for developers over
Core Data. To help you learn how to implement SQLite within an iOS application I have written this
tutorial to demonstrates how to load and display data from a SQLite database in an UITableView and
to display selected details in a DetailViewController based on a user's selection. The tutorial also
shows how to insert data using an input form.
Create the Database
Before we can access the data in the database, it has to be created. SQLite can dynamically create
databases if it doesn't exists with the open command. This operation should be performed in the
AppDelegate when the app is loaded.
Open the AppDelegate implementation file and in the didFinishLaunchingWithOptions method
declare a variable for any possible error messages, NSError *errMsg.
Also add a BOOL variable which will be used to check to see if the database already exists in the
Document directory. If it doesn't exist, create it otherwise do nothing.
To get a handle on the Documents directory we will use the NSSearchPathForDirectoriesInDomains
method from the Foundations Framework. This method retrieves an array of all the directories in the
search path. For this example, the search path is the Document directory, NSDocumentDirectory,
which is a constant in the Foundations Framework.
Since the array will contain only one entry, the Documents directory, we can use the
ObjectAtIndex:0 to retrieve the first entry and store the value in a NSString variable,documentPath.
The NSDocumentDirectory returns the complete path to the Documents directory and so all we need
to do next is append the name of the database we will create and use to store the data.
The next line of code, fileExist = [[NSFileManager alloc] fileExistsAtPath:documentPath]; checks to
see if the database already exists at the path specified with the documentPath variable. If it does,
the return value will be YES. Otherwise the fileExistAtPath will return NO.
If the fileExist is false issue a open database command using the sqlite3_open SQLite command. If
the database fails to open (or get created) by checking the return code SQLITE_OK, log an error and
exit. Otherwise we will setup the query to create a table, todoTbl if it doesn't exist.
The sqlite3_exec command, used here, is a handy and compact command that encapsulates the
prepare statement, the step statement and the finalize statement which are the statements to
execute a SQLite query.
If the sqlite3_exec return code from the SQLITE_OK, we will have completed the database setup
process. The complete code is provided in code listing 1 below.
Code listing 7
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
NSLog(@"There is a problem with prepare statement");
return;
else
while (sqlite3_step(sqlStatement)==SQLITE_ROW)
char * checkChar = (char*)sqlite3_column_text(sqlStatement, 1);
if (checkChar!=NULL)
ToDo * newToDo = [[ToDo alloc] init];
newToDo.todoName = [NSString stringWithUTF8String:(char *)sqlite3_column_text(sqlStatement,
0)];
newToDo.todoDescription= [NSString stringWithUTF8String:(char
*)sqlite3_column_text(sqlStatement, 1)];
//get date value
const unsigned char *charDate = sqlite3_column_text(sqlStatement, 2);
if(charDate!=NULL)
//Convert char Date value to NSString
NSString *strDate = [[NSString alloc] initWithUTF8String: (const char *) charDate];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"MM/dd/yyyy"];
newToDo.todoDate = strDate;
else
newToDo.todoDate = @"";
[todoArr addObject:newToDo];
newToDo = nil;
sqlite3_finalize(sqlStatement);
sqlite3_close(db);
Code listing 13
-(void) upsertToDo:(NSString *)todoName :(NSString *) todoDescription :(NSString *)todoDate
//Get list of directories in Document path
NSArray * dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
//Define new path for database
NSString * documentPath = [[dirPath objectAtIndex:0]
stringByAppendingPathComponent:@"taskDb.db"];
if(!(sqlite3_open([documentPath UTF8String], &db) == SQLITE_OK))
NSLog(@"An error has occured.");
return;
else
NSString *insertSQL = [NSString stringWithFormat:
@"INSERT INTO todoTbl(todoName, todoDescription, todoDate) VALUES ('%@','%@','%@')",
todoName,todoDescription, todoDate];
const char *sql = [insertSQL UTF8String];
sqlite3_stmt *sqlStatement;
if(sqlite3_prepare_v2(db, sql, -1, &sqlStatement, NULL) != SQLITE_OK)
NSLog(@"Problem with prepare statement");
return;
else
if(sqlite3_step(sqlStatement)==SQLITE_DONE)
sqlite3_finalize(sqlStatement);
sqlite3_close(db);
Code listing 16
#import <UIKit/UIKit.h>
#import "DbOps.h"
#import "ToDo.h"
#import "klViewController.h"
#import "todoDetailViewController.h"
@interface ListViewController : UITableViewController<UITableViewDataSource,
UITableViewDelegate>
@property(nonatomic, strong) ToDo * todoItem;
@property(nonatomic, strong) DbOps * ops;
@property(nonatomic, strong) NSMutableArray * todoArray;
@property (strong, nonatomic) IBOutlet UITableView *todoTable;
@end
With the UITableViewController selected, create a navigation controller using the (Editor->Embed
In->Navigation Controller) command from the Editor menu in Xcode.
Next add a Navigation Item button to the Navigation Bar in the UITableViewController and add a
Push Segue to the klViewController that was initially created with the project. Read this tutorial"
IOS 5 Storyboarding Tutorial using Segues | Scenes | View Controllers | Navigation", if you need
help creating Scenes and Segues.
The complete layout of the Storyboard is presented in Figure 1 below
Implement the View Controller
Now that the Storyboard is done, we will add code to the implementation files.
Open the klViewController implementation, or whatever you call it the initial view controller when
you created the project
In the saveToDo method add the following code, listing 17, to pass the values of the IBOutlets
(UITextFields) to the upsertToDo method:
That is all that is needed for the klviewController implementation
In the ListViewController, in the viewWillAppear method, add the following code, listing 18, to
initialize the todoArray, initialize the ops instance variable, call the selectTodo method and assign
the values from the todoArr to the todoArray variable. This will load any existing items into the
UITableView when it is loaded.
To be able to reload any new data at runtime, call the reloadData method as in coding listing 18.
In Summary
Below are screenshots of the running app. Of course this is a rudimentary design and its objective is
to provide an example of how to display content from a SQLite database in an UITableView and also
how to push the details to a second view controller. However in a real production app, more error
checking and proper controls and validation must be implemented, not to mention proper testing to
make sure the application performs as desired. The code itself is only for demonstration purposes
only and the author doesn't provide any guarantees on its functionality in any application where it is
implemented.
http://klanguedoc.hubpages.com/hub/iOS-5-How-To-Display-SQLite-Data-in-a-UITableView-and-Detai
lViewController