iPhoneアプリでFMDBを使ったときのメモ
FMDBを使うとSQLiteを簡単に扱うことができます。
iPhoneアプリでSQLiteを使用する必要があったので、この辺りを参考に導入しました。
SQLiteを利用する方法
iPhone Programming Tutorial – Creating a ToDo List Using SQLite Part 1
準備
FMDBをiPhoneアプリで使うには、以下の準備が必要です。
・SQLiteをアプリから使えるようにする。
・SQLiteのDBファイルをアプリのリソースに追加する。
・FMDBライブラリを組み込む
SQLiteのDBファイルをアプリのリソースに追加
SQLiteのツールなどでデータベースファイルを作成し、XcodeからResourcesに追加する
最初から必要なデータなどを登録しておけるので便利
FMDBライブラリの組み込み
下記サイトより、fmdbをダウンロード
github fmdb
展開したファイルより、以下のファイルをXcodeから追加する
FMDatabase.h FMDatabase.m FMDatabaseAdditions.h FMDatabaseAdditions.m FMResultSet.h FMResultSet.m
以上で使えるようになったはずです。
サンプル
かなりすっきりしたコードがかけます。
アカウント操作を行うモデルクラスをサンプルとしてつけておきます。
DB初期化クラス SqliteDB.h SqliteDB.m
UIApplicationDelegate継承クラスあたりで、アプリ起動時に一度だけよびだしてください。
initializeDatabaseIfNeeded
SQLiteデータベースファイルが実行ディレクトリにない場合、リソースファイルからコピーして作成します。
シミュレータのとき
コピー先「/Users/ユーザ名/Library/Application Support/iPhone Simulator/バージョン/Applications/xxxxx」
コピー先のファイルを削除すれば初期化できます。
getDatabaseFilePath
SQLiteデータベースファイルのパスを返します。
SqliteDB.h
#import <sqlite3.h> #define BASEDB @"sample.sqlite" #define DBPATH @"sampledata.sqlite" #define DBFLAG @"dbflag" @interface SqliteDB : NSObject { } -(void) initializeDatabaseIfNeeded; +(NSString*) getDatabaseFilePath; @end
SqliteDB.m
#import "SqliteDB.h" @implementation SqliteDB -(void) initializeDatabaseIfNeeded { NSFileManager* fileManager = [NSFileManager defaultManager]; NSError* error; NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* documentsDir = [paths objectAtIndex:0]; NSString* flagPath = [documentsDir stringByAppendingPathComponent:DBFLAG]; // dbflag file check if (![fileManager fileExistsAtPath:flagPath]) { NSString* dbpath = [SqliteDB getDatabaseFilePath]; NSString* templateDBPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:BASEDB]; // remove database file if([fileManager fileExistsAtPath:dbpath] == YES) { [fileManager removeItemAtPath:dbpath error:NULL]; } // copy database file if (![fileManager copyItemAtPath:templateDBPath toPath:dbpath error:&error]) { [error localizedDescription]; return; } // dbflag file create [fileManager createFileAtPath:flagPath contents:nil attributes:nil]; } } +(NSString*) getDatabaseFilePath { NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString* documentsDir = [paths objectAtIndex:0]; return [documentsDir stringByAppendingPathComponent:DBPATH]; } - (void)dealloc { [super dealloc]; } @end
アカウントモデルクラス AccountModel.h, AccountModel.m
ユーザアカウント操作クラス。サンプルです。
selectAll
全レコード取得
countAll
全レコード件数取得
selectById:(int)recordId
レコード取得(ID)
saveId:(int)recordId gender:(int)gender userName:(NSString*)userName
レコード追加、更新
deleteId:(int)recordId
レコード削除
AccountModel.h
#import <sqlite3.h> #import "FMDatabase.h" @interface AccountModel : NSObject { int recordId; int gender; NSString* userName; } @property (nonatomic, readwrite) int recordId; @property (nonatomic, readwrite) int gender; @property (nonatomic, readwrite, retain) NSString* userName; +(NSMutableArray*)selectAll; +(int) countAll; +(AccountModel*)selectById:(int)recordId; +(int) saveId:(int)recordId gender:(int)gender userName:(NSString*)userName; +(void) deleteId:(int)recordId; // local +(AccountModel*) createAccountModel:(FMResultSet*)rs; @end
AccountModel.m
#import "AccountModel.h" #import "SqliteDB.h" #import <sqlite3.h> #import "FMDatabase.h" #import "FMDatabaseAdditions.h" @implementation AccountModel @synthesize recordId, gender, userName; -(id) init { [super init]; recordId = -1; return self; } +(int) countAll { NSString* dbPath = [SqliteDB getDatabaseFilePath]; NSString* sql1 = [NSString stringWithFormat:@"select count(*) as count from Account"]; FMDatabase* db = [FMDatabase databaseWithPath:dbPath]; if(![db open]) { return 0; } [db setShouldCacheStatements:YES]; FMResultSet* rs = nil; rs = [db executeQuery:sql1]; int count = 0; if ([rs next]) { // just print out what we've got in a number of formats. count = [rs intForColumn:@"count"]; } [rs close]; [db close]; return count; } /** * select all */ +(NSMutableArray*)selectAll { NSString* dbPath = [SqliteDB getDatabaseFilePath]; NSString* sql1 = [NSString stringWithFormat:@"select * from Account order by userName, gender, id"]; NSMutableArray* ret = [[[NSMutableArray alloc] init] autorelease]; FMDatabase* db = [FMDatabase databaseWithPath:dbPath]; if(![db open]) { return nil; } [db setShouldCacheStatements:YES]; FMResultSet* rs = nil; rs = [db executeQuery:sql1]; while ([rs next]) { AccountModel* account = [AccountModel createAccountModel:rs]; [ret addObject:account]; } [rs close]; [db close]; return ret; } /** * select by id */ +(AccountModel*)selectById:(int)recordId { NSString* dbPath = [SqliteDB getDatabaseFilePath]; NSString* sql = [NSString stringWithFormat:@"select * from Account where id = ?"]; FMDatabase* db = [FMDatabase databaseWithPath:dbPath]; if(![db open]) { return nil; } [db setShouldCacheStatements:YES]; FMResultSet* rs = nil; rs = [db executeQuery:sql, [NSNumber numberWithInt:recordId]]; AccountModel* account = nil; if ([rs next]) { account = [AccountModel createAccountModel:rs]; } [rs close]; [db close]; return account; } +(AccountModel*) createAccountModel:(FMResultSet*)rs { AccountModel* account = [[[AccountModel alloc] init] autorelease]; account.recordId = [rs intForColumn:@"id"]; account.gender = [rs intForColumn:@"gender"]; account.userName = [rs stringForColumn:@"userName"]; return account; } /** * save record */ +(int) saveId:(int)recordId gender:(int)gender userName:(NSString*)userName { NSString* dbPath = [SqliteDB getDatabaseFilePath]; NSString* sql = [NSString stringWithFormat:@"%@%@", @"insert or replace into Account (id, gender, userName)", @" values (?, ?, ?)"]; FMDatabase* db = [FMDatabase databaseWithPath:dbPath]; if(![db open]) { return -1; } [db setShouldCacheStatements:YES]; if (recordId == -1) { [db executeUpdate:sql, [NSNull null], [NSNumber numberWithInt:gender], userName]; } else { [db executeUpdate:sql, [NSNumber numberWithInt:recordId], [NSNumber numberWithInt:gender], userName]; } int lastInsertRowId = [db lastInsertRowId]; [db close]; return lastInsertRowId; } +(void) deleteId:(int)recordId { NSString* dbPath = [SqliteDB getDatabaseFilePath]; NSString* sql = @"delete from Account where id = ?"; FMDatabase* db = [FMDatabase databaseWithPath:dbPath]; if(![db open]) { return; } [db setShouldCacheStatements:YES]; [db executeUpdate:sql, [NSNumber numberWithInt:recordId]]; [db close]; } - (void)dealloc { [userName release]; [super dealloc]; } @end
使い方
// DBファイル初期化 SqliteDB* db = [[SqliteDB alloc] init]; [db initializeDatabaseIfNeeded]; [db release]; // account model 取得 AccountModel* account = [AccountModel selectById:1];
「FMDB」かなり使えます。おすすめです。