2014年3月4日

在iOS應用程式中使用sqlite

SQLite是輕量級的資料庫管理系統,多半用於手機應用程式中。SQLite支援大多數常見的SQL語句,對於已經熟悉在大型伺服器上使用SQL語言的人來說,是相當容易上手的。

以下,將介紹如何在iOS應用程式中使用SQLite。

建立sqlite檔案

sqlite檔案是所有SQLite資料實體所存放的位置。 網路上已有諸多SQLite工具程式可以建立sqlite檔案。

如Firefox的附加元件SQLite Manager

建立好Table之後,將sqlite檔案加入專案中即可。

拷貝sqlite檔案至documents目錄底下

sqlite檔案應存放在應用程式的documents目錄底下,假設我們的sqlite檔案的檔案名稱為myproject.sqlite,則取得該路徑的方式如下:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);

NSString *documentsDirectory = [paths objectAtIndex:0];

//sqlite檔案在documents目錄底下的路徑
NSString *pathInDoc = [documentsDirectory stringByAppendingPathComponent:@"myproject.sqlite"]; 

iOS應用程式應該在第一次執行時,將sqlite檔案由專案中拷貝到至documents目錄底下。

因此,我們在程式每一次啟動時,檢查documents目錄底下的sqlite檔案是否存在:

//檢查sqlite檔案是否存在
if([fileManager fileExistsAtPath:pathInDoc]) {

    //sqlite檔案不存在,由專案中拷貝至documents目錄底下
    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSString *defaultDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"myproject.sqlite"];
    int result = [fileManager copyItemAtPath:defaultDBPath toPath:pathInDoc error:&error];
}

使用C語言API

欲使用C語言API存取SQLite資料庫,必須在專案中加入libsqlite3.0.dylib

並在程式中引入標頭檔:

#import <sqlite3.h>

開啟資料庫,建立sqlite3物件

在存取資料庫前,必須先開啟資料庫,建立sqlite3物件。 下方範例中,pathInDoc為上方範例中取得的sqlite檔案路徑。 由於使用的是C語言API,因此,需要使用NSString的UTF8String方法,來取得C式字串(char*);

sqlite3 *database;
int result = sqlite3_open([pathInDoc UTF8String], &database);
if (result != SQLITE_OK){
    //錯誤處理
}

在以下存取資料庫的C API中,其參數都需要用到sqlite3物件。

寫入資料庫(C API)

首先,使用sqlite3_prepare_v2函式建立sqlite3_stmt物件,並傳入SQL語句參數。SQL中可以使用問號,於稍後程式中輸入參數。

在sqlite3_stmt建立後,再使用sqlite3_bind_int函式設定各個問號所代表的參數內容。

參數設定完成後,最後使用sqlite3_step函式來執行。完整範例如下:

char *sqlCString = "UPDATE Content SET isFavorite = ? WHERE id = ? ;";
sqlite3_stmt *stmt;
int result = sqlite3_prepare_v2(database, sqlCString, -1, &stmt, nil);
if(result != SQLITE_OK) {
    //錯誤處理
    return;
}

//設定isFavorite(第1個問號)值為1
sqlite3_bind_int(stmt, 1, 1);   

//設定id(第2個問號)值為5
sqlite3_bind_int(stmt, 2, 5);   //設定id值為5

result = sqlite3_step(stmt);
if(result != SQLITE_DONE) {
    //錯誤處理 NSLog(@"An error occurs when executing sql! (%i)",result);
}
sqlite3_finalize(stmt);

執行完寫入後,務必執行sqlite3_finalize,釋放相關資源。

讀取資料庫(C API)

讀取資料庫時,同樣使用sqlite3_prepare_v2函式建立sqlite3_stmt物件、傳入SQL語句參數。

取回結果時,可以使用sqlite3_column_intsqlite3_column_text函式,以取得對應資料形態的結果。

char *sqlCString = "SELECT c.subject_id, c.title FROM Content c WHERE c.id = ?;";
sqlite3_stmt *stmt;
int result = sqlite3_prepare_v2(database, sqlCString, -1, &stmt, nil);

//設定id(第1個問號)值為1
sqlite3_bind_int(stmt, 1, 5);

while(sqlite3_step(statement) == SQLITE_ROW){
    //取得第1個參數 (整數形態)
    int subectID = sqlite3_column_int(statement, 1);

    //取得第2個參數 (字串形態)
    NSString* title = [[NSString stringWithUTF8String:(char *)sqlite3_column_text(statement, 2)] copy];

}
sqlite3_finalize(stmt);

執行完讀取後,同樣需執行sqlite3_finalize,釋放相關資源。

使用FMDB API

雖然C語言API並不算是太難使用,但畢竟是純C語言界面,與Objective-C之間往往還需要轉換資料形態才能使用(如:NSString與char陣列)。為了能讓程式碼更為簡潔、更易於管理,可以使用FMDB

FMDB是一套以Objective-C寫成的wrapper,將C語言API包起來藏在內部,讓其他開發者能直接使用Objective-C界面來存取資料庫,無需考慮Objective-C與C語言介接的細節。

欲使用FMDB,只要下載FMDB專案,在我們自己的專案中加入FMDB資料夾。

並在程式中引入FMDB標頭檔:

#import "FMDatabase.h"

開啟資料庫(FMDB API)

使用FMDB存取資料庫前,需要建立建立FMDatabase物件。

FMDatabase *fmdb = [FMDatabase databaseWithPath:pathInDoc];
if (![fmdb open]) {
    //錯誤處理 NSLog(@"fmdb open error");
}

寫入資料庫(FMDB API)

使用FMDB寫入資料庫的範例,比使用C API簡潔很多。範例如下:

NSString *sql = "UPDATE Content SET isFavorite = ? WHERE id = ? ;";
int updateCount = 0;
if([fmdb executeUpdate:sql,@1,@5]) {
     updateCount = [fmdb changes];
}
else {
    //錯誤處理
}
[fmdb close];

讀取資料庫(FMDB API)

使用FMDB讀取資料庫也同樣簡潔:

FMResultSet *rs = [fmdb executeQuery:@"SELECT c.subject_id, c.title FROM Content c WHERE c.id = %i;", @5];

while ([rs next]) {
    //取得第1個參數 (整數形態)
    int subectID = [rs intForColumn:@"subject_id"];

    //取得第2個參數 (字串形態)
    NSString* title = [rs stringForColumn:@"title"];
}
[fmdb close];

快速讀取

此外,FMDB還提供了便捷的API。

像是,如果我們只需要取得一個SQL語句回傳的某個結果:

int score = [fmdb intForQuery:@"SELECT score FROM Student WHERE Name = ?",@"Michael”];

一行就可以解決。

結語

撰寫手機應用程式石,存放資料到手機上,以及讀取先前儲存的資料,幾乎是一定會遇到的需求。而SQLite則提供了大家所熟悉的解決方案。對於熟悉SQ語法的人,在撰寫手機應用程式時,更應了解SQLite的使用方式。