Persistent Data • We have used files already (Favorite Twitter Searches) • Core Data • SQLite • Can also access data from other apps (photo, calendar, ..) Core Data • Object-Oriented data model framework to build apps using MVC architecture • Interface Builder provides pre-built Core Data controller objects with a lot of code already pre-written; uses SQLite underneath but you do not have to write SQL code SQLite • Lightweight, powerful relational database engine • Popular with people who already know SQL • Data is stored in regular files but we use SQL syntax to access and manipulate the data • http://developer.apple.com/library/mac/#document ation/Darwin/Reference/ManPages/man1/sqlite3.1 .html SQLite • Sqlite3 is a command line interface for Sqlite version 3 • See apple doc at http://developer.apple.com/library/mac/#doc umentation/Darwin/Reference/ManPages/m an1/sqlite3.1.html • And also http://www.sqlite.org/ SQLite • Old fashioned C library • Pointer, pointer of pointer, address of operator • *, **, & notations • an NSString will have to be converted to a char* SQLite • Create a database • Create a table • Insert, delete, update, select operations Creating a database • SQLite uses flat files (not B-trees) • Similar to “finding” a file to write/append to it • Find a directory where we can write • Define a file name for the database • Create it Creating a database • NSArray *paths = NSSearchPathForDirectoriesInDomain( NSDocumentDirectory, NSUserDomainMask, YES ); • NSString *doc = [paths objectAtIndex: 0]; • store full file path in an instance variable named dbFile – we will need it in several places Creating a database • dbFile = [doc stringByAppendingPathComponent: @”users.db”]; • NSFileManager *manager = [NSFileManager defaultManager]; • if( [manager fileExistsAtPath: dbFile] ) • /* create database and table */ Creating a database • sqlite3_open function: opens a sqlite database file • int sqlite3_open( const char *filename, sqlite3 **ppDb ); • Filename = same as dbFile, in C (need to convert NSString to char *) – read only • ppDb = pointer to a pointer to a sqlite3 variable; sqlite3_open will write to it and create that database handle Creating a database • sqlite3_open ‘s default behavior is to open a database file for reading and writing • If the file exists, it is open • If the file does not exist, it is created • sqlite3_open_v2 provides 2 more parameters for more control (read only, ..) Creating a database • If successful, SQLITE_OK (i.e. 0) is returned; otherwise some error code is returned • Can declare 2nd parameter as an instance variable (used in many places) • sqlite3 *db; • use &db as 2nd argument of sqlite3_open Creating a database • 1st parameter is of type char * we need a C like string • In NSString class, we have the method: • -(char *) UTF8String; • It converts a NSString to a char * • UTF8 = Unicode Transformation Format (8 bit) Creating a database • In NSString class, we have the method: • -(char *) UTF8String; const char *dbPath = [dbFile UTF8String]; if( sqlite3_open( dbPath, &db ) == SQLITE_OK ) { // database is open // create a table } Creating a table • sqlite3_exec function • int sqlite3_exec( sqlite3 *db, const char *sql, int (*callback) (void*,int,char**,char**), void *, char **errmsg ); • db = an open database • sql = sql statement to be executed Creating a table • 3rd parameter: Callback function • 4th parameter: 1st argument to callback function • Error message to be written in 5th parameter • Typically NULL, NULL, &error where we declared error earlier: • char *error; Creating a table const char *stmt = “create table users( id int, name text, age int )”; sqlite3_exec( db, stmt, NULL, NULL, &error ); • // the table users has been created sqlite3_close( db ); SQLite data types • Not many data types are supported my sqlite • NULL, int, text, real, blob For bool, use an int For strings and dates/times, use text For floats and doubles, use real Check if successful • Open a terminal window (inside Utilities folder) • Look for and find file path • sqlite3 users.db • gives you an sql prompt • You are inside the users.db database Check if successful • .tables (no ;) lists tables • select * from users; • .schema users (no ;) show create statement for users table • .exit (no ;) exits sqlite Insert statement • Use sqlite3_open to open the database • Use sqlite3_exec to execute the insert statement if( sqlite3_open( dbPath, &db ) == SQLITE_OK ) { // make insert statement // execute insert statement } Insert statement NSString *insert = [NSString stringWithFormat: @”insert into users values( 1, ‘mike’, 24 )”]; // convert to char * const char *stmt = [insert UTF8String]; // OR char *stmt = “insert into users values( 2, ‘jane’, 22 )”; Insert statement // execute insert sqlite3_exec( db, stmt, NULL, NULL, &error ); sqlite3_close( ); Update and delete • • • • Same as insert, just change the sql string Open database using sqlite3_open Make sql statement Execute statement using sqlite3_exec Select statement • sqlite3_exec is actually a function that combines 2 other functions: • sqlite3_prepare (or sqlite3_prepare_v2) • sqlite3_step • for select, we use sqlite3_prepare_v2 (version 2, more recent) and sqlite3_step Select statement • Use sqlite3_open to open the database if( sqlite3_open( dbPath, &db ) == SQLITE_OK ) { // make select statement // execute select statement and process results } Select statement NSString *query = @”select * from users”; const char *queryStmt = [query UTF8String]; • int sqlite3_prepare_v2( sqlite3 *db, const char *zSql, int nByte, sqlite3_stmt **ppStmt, const char **pzTail ); • 5 parameters Select statement • db = database handle • zSql = sql query ( a string) • nByte zSql string read to the nByte-th byte or \000, or \u0000, whichever comes first • ppStmt = a statement handle (to be written to by function sqlite3_prepare_v2) will be used by sqlite3_step function • pzTail = remaining (unused) portion of sql string Select statement • 3rd and 5th argument: if nByte is < 0 (-1 for example) whole sql string is used, pass NULL for pzTail • 4th argument: Need to declare a sqlite3_stmt * variable (named stmt for example) and pass its address (as in &stmt) Select statement if( sqlite3_prepare_v2( db, queryStmt, -1, &stmt, NULL ) == SQLITE_OK ) { // process the results one row at a time // use sqlite3_step function } // SQLITE_OK’s value is 0 Select statement • int sqlite3_step( sqlite3_stmt *stmt ) • Returns SQLITE_ROW if some data is returned • SQLITE_ROW’s value is 100 • can use while loop to process rows Select statement while(sqlite3_step( stmt ) == SQLITE_ROW) { // process current row // retrieve values at various columns // column index starts at 0 } Select statement • Use the function • dataType sqlite3_column_dataType( sqlite3_stmt *stmt, int columnIndex ) • dataType = blob, text, double, int, .. Select statement char *nameChars = (char *) sqlite3_column_text( stmt, 1 ); int age = sqlite3_column_int( stmt, 2 ); NSString *name = [ NSString stringWithUTFString: nameChars ]; • do something with name and age