好滴~離上次發文又給他隔了三個月,為什麼咧??因為林盃我很忙,這三個月我跑去訂婚、結婚、歸寧外加峇里島蜜月,所以部落格就這麼給他放著了。以為這裡不會再更新的朋友們~快回來哦~有新文章了。
這次要分享的是在iOS中使用SQLite。其實我對SQLite一點概念都沒有,因為一直沒有機會使用它。有時候突然想到,就會找幾本手邊的工具書或在網路上找尋在iOS中使用SQLite的教學。但是每次學,每次失敗,讓我愈來愈討厭SQLite 囧。直到有一次在網路上發現了FMDB這個東西,才發現不是SQLite很難學,而是SQLite的C API對初學者來說實在太麻煩太瑣碎,難度太高,難怪我怎麼學都學不會。FMDB說穿了其實只是把C API包裝成簡單易用的Objective-C物件。不過這對我這個SQLite初學者來說,可是大大減低了上手的難度。有了FMDB,寫程式時只要專心在SQLite的語法上,而不用去理那堆有看沒有懂的C API,實在是件快樂的事情。
廢話不多說,先來安裝FMDB吧!
首先到這裡下載FMDB的source code,接著在解開的檔案裡,把src資料夾下除了fmdb.m的檔案加入到自己的iOS專案,最後在專案中加入libsqlite3.dylib這個函式庫就可以了。啥?有人問為什麼不用加入fmdb.m?簡單講,這個檔案是fmdb的使用說明。裡面的註解清楚,範例又簡單,如果有興趣,直接看fmdb.m,大概就會用fmdb了。
以下介紹幾個常用的指令,分享給大家:
-開啟/關閉資料庫
使用資料庫的第一件事,就是建立一個資料庫。要注意的是,在iOS環境下,只有document directory 是可以進行讀寫的。在寫程式時用的那個Resource資料夾底下的東西都是read-only。因此,建立的資料庫要放在document 資料夾下。方法如下:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@”MyDatabase.db”];
FMDatabase
*db = [FMDatabase databaseWithPath:dbPath] ;
if (![db open]) {
NSLog(@“Could not open db.”);
return ;
}
通常這段程式碼會放在UIViewController中viewDidLoad的函式裡。指定路徑後,用[FMDatabase databaseWithPath:]回傳一個FMDatabase物件,如果該路徑本來沒有檔案,會新增檔案,不然會開啟舊檔。最後呼叫[db open]可以開啟該資料庫檔案,[db close]則關閉該檔案。
-建立table
如果是新建的資料庫檔,一開始是沒有table的。建立table的方式很簡單:
[db executeUpdate:@”CREATE TABLE PersonList (Name text, Age integer, Sex integer, Phone text, Address text, Photo blob)”];
這是FMDB裡很常用的指令,[FMDatabase_object executeUpdate:]後面用NSString塞入SQLite語法,就解決了。因為這篇主要是在講FMDB,所以SQLite的語法就不多說了,上述程式碼建立了一個名為PersonList的table,裡面有姓名、年齡、性別、電話、地址和照片。(嗯….很範例的一個table)
-插入資料
插入資料跟前面一樣,用executeUpdate後面加語法就可以了。比較不同的是,因為插入的資料會跟Objective-C的變數有關,所以在string裡使用?號來代表這些變數。
[db executeUpdate:@”INSERT INTO PersonList (Name, Age, Sex, Phone, Address, Photo) VALUES (?,?,?,?,?,?)”,
@”Jone”, [NSNumber numberWithInt:20], [NSNumber numberWithInt:0], @“091234567”, @“Taiwan, R.O.C”, [NSData dataWithContentsOfFile: filepath]];
其中,在SQLite中的text對應到的是NSString,integer對應NSNumber,blob則是NSData。該做的轉換FMDB都做好了,只要了解SQLite語法,應該沒有什麼問題才是。
-更新資料
太簡單了,不想講,請看範例:
[db executeUpdate:@”UPDATE PersonList SET Age = ? WHERE Name = ?”,[NSNumber numberWithInt:30],@“John”];
-取得資料
取得特定的資料,則需使用FMResultSet物件接收傳回的內容:
FMResultSet *rs = [db executeQuery:@”SELECT Name, Age, FROM PersonList”];
while ([rs next]) {
NSString *name = [rs stringForColumn:@”Name”];
int age = [rs intForColumn:@”Age”];
}
[rs close];
用[rs next]可以輪詢query回來的資料,每一次的next可以得到一個row裡對應的數值,並用[rs stringForColumn:]或[rs intForColumn:]等方法把值轉成Object-C的型態。取用完資料後則用[rs close]把結果關閉。
-快速取得資料
在有些時候,只會query某一個row裡特定的一個數值(比方只是要找John的年齡),FMDB提供了幾個比較簡便的方法。這些方法定義在FMDatabaseAdditions.h,如果要使用,記得先import進來。
//找地址
NSString *address = [db stringForQuery:@”SELECT Address FROM PersonList WHERE Name = ?”,@”John”];
//找年齡
int age = [db intForQuery:@”SELECT Age FROM PersonList WHERE Name = ?”,@”John”];
大概就是這樣囉~對於在Objective-C上使用SQLite有困難的朋友,看完之後是不是覺得一切都變的很簡單呢?趕快去試試吧~
我個人真的非常期待你出書~XD
你覺得我這麼懶,出的了一本書嗎XD
想深入學習cocos2d,
除了官方網站外,
不知道有沒有推薦的參考資料呢?
總覺得跟itune上面的遊戲程式,
level天差地遠!
學長酷阿!簡單易懂
您好, 我用 iOS 4.3 搭配 XCode 4.0.1 開發.
但我看到一本電子書的資料說, 在:
/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib
會找到:
libsqlite3.dylib
似乎 iOS 已經整合 SQLite 了?
我在這本電子書裡面, Page 287 看到的.
Click to access %5BiPhone%E5%BC%80%E5%8F%91%E4%B9%A6%E7%B1%8D%E5%A4%A7%E5%85%A8%5D.Beginning.iPhone.SDK.Programming.with.Objective-C%28Wrox.2010-01%29.pdf
用法似乎跟您寫的類似, 是不是 iOS 已經可以像 FMDB 一樣使用 Objective-C 語法來用了?
謝謝~
hello,
iOS本來就整合了SQLite在裡面,但你得去呼叫最原始的C API去使用SQLite,我個人是覺得用起來不直覺又麻煩。FMDB則是幫你把所有的C API都包進一個objective-C物件裡,所以使用上來說比較方便。這就好像iOS本身支援OpenGL ES,但你不會去直接用他,而是靠cocos2d幫忙。FMDB不是官方的模組,需要自己import進來。
補充說明,那本書上教的就是最原始的SQLite C API。如果您覺得那樣比較方便,其實就不需要FMDB了。
恩~我瞭解了.
謝謝喔~
您好,我用XCODE4開發IPHONE上APP,現在遇到一個問題,在使用您上述的程式碼建立新的資料庫時,卻發生在document資料夾中,沒有看到我所建立的資料庫的檔案,但是確定可以在資料庫上新增、查詢。想請這問這是回事?謝謝您
請問您所說的“在document資料夾中沒看到所建立的資料庫”,這個document資料夾的路徑為何呢?
您好,我是直接使用NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentDirectory = [paths objectAtIndex:0];
NSString *dbPath = [documentDirectory stringByAppendingPathComponent:@”MyDatabase.db”];
FMDatabase*db = [FMDatabase databaseWithPath:dbPath] ;
這段程式碼。並且建立TALBE和輸入一筆資料。
再來搜尋建立的資料庫檔案,都搜尋不到檔案。
hello,我想問的是,您是怎麼“搜尋建立的資料庫檔案”? 程式碼?finder?
不好意思,是用FINDER的搜尋去找的。
finder。。。您該不會是去帳號下的Document資料夾下找吧?iPhone模擬器的document不在那裡喔!
原來如此,我一直以為是在那邊,怪不得找不到。
很謝謝您的解答。
那想請教一下如何判斷table 是否存在
[db executeUpdate:@”CREATE TABLE PersonList (Name text, Age integer, Sex integer, Phone text, Address text, Photo blob)”];
會自動判斷嗎 如果不存在才建立
要用這個”CREATE TABLE IF NOT EXISTS my_table( filed1 char(20) );”
非常感謝你的回覆
請問-刪除重複資料要怎麼做?
我有參考http://www.dotblogs.com.tw/lastsecret/archive/2010/07/13/16532.aspx
的方式,1.DELETE Product where ID NOT IN (Select Max(ID) From [Product] Group By 產品名稱)2.Select * From [Product] Where ID In (Select Max(ID) From [Product] Group By 產品名稱)
但是沒有用,請問要怎麼做?謝謝
另外還看到http://blog.miniasp.com/post/2010/08/12/Remove-duplicate-rows-from-a-table-in-SQL-Server.aspx
說到“若要避免資料重複,建議額外建立含有多個欄位的「唯一索引鍵」,從資料庫層級就阻擋所有可能重複資料的出現。”
我主要是要避免資料重複,那我該怎麼建立含有多個欄位的「唯一索引鍵」?
謝謝!!
ㄟ…老實說SQLite我不是專家,可能要請您另請高明了。
你好請問一下,假設我想用一個singleton的class專門來處理DB的建立,寫入跟刪除等功能
我應該要在哪邊建立table ?
總覺得有點看不太懂何時應該建立Table?
使用FMDB是不用先拉任何.sqlite 檔案到Project裡面
然後就會自動產生.sqlite檔案在Docment裡面嗎?
我有打開看,看起來是有產生檔案,不過印不出任何資料
不好意思我發現我有寫檔案了,應該是讀出的時候有問題,我再查看看。
我知道問題了…我在參考你的程式碼的時候
在這行FMResultSet *rs = [db executeQuery:@”SELECT Name, Age, FROM PersonList”];
Age後面還有多一個 ” , ” 沒發現,會導致無法select 結果出來。FMDB真是三八啦,小小逗號還計較這麼多
我想請問 為何我把fmdb 您說的那幾檔案 add 進我的project裡
fmdatabase 出現 一大堆錯誤
請問 是為什麼呢?
我方法錯嘛?
那個。。。。。您的錯誤是什麼?至少貼出來吧?不然我也不知道錯在哪說@@
不好意思 我還是新手
db 函示庫 我該怎麼新增呢??
我用的是xcode 4.2版本的
感謝您
呃。。。不太懂你的問題,你想新增什麼??
您好 我解決了基本錯誤…..
那個錯誤是xcode4.2的問題 自動釋放內存
我想問的是 享用fmdb 只要單純的把fmdb那幾個資料 丟進去 並在framwork那增加sqlite3就好了嗎??
不知可否在問您 由於小的最近在做專題 這個程式需要用到資料夾
假設 畫面有兩個textfield 一個button
我想要在textfield 1 中 輸入數字 然後按下button 後
這筆數字 會存到 資料庫中 並且同時被取出 在text 2 中顯示出來
不知道這個該怎麼做…. 小弟隊資料庫 目前真的不熟
希望可以幫幫忙 讓我的專題可以順利完成 ><
不知道您有沒有 即時通 或是 qq 之類的
可以讓我有問題時請教您><
感謝
請問iPhone模擬器的document資料夾在哪?小弟翻遍整個專案找不著阿==a
你的家目錄/Library/Application Support/iPhone Simulator/5.0
裡面有一堆被裝在模擬器裡的app,找到以後,裡面的document資料夾才是你要的。
翻遍專案當然找不到= =
老大,我還是找不著阿TT我用的是LION的系統,xcode4.1,雖然有Application Support跟IPhone Simulator這兩個資料夾,但Iphone Simulator卻不是在Application Support的子目錄下,直接搜尋MyDatabase完全找不著阿==資料能插入也能取出,但找不到資料庫所在的位置阿冏
我剛試著把路徑印出來,顯示/Users/ctp/Library/Application Support/iPhone Simulator/4.3.2/Applications/,但奇怪的是我從find去找卻找不到這個路徑==搜尋4.3.2也找無結果,請問這是怎麼一回事阿==
老大阿,我的ctp底下找不到Library耶==a難怪mac也會隱藏資料夾嗎?
老大阿,我的ctp底下找不到Library耶==a難道mac也會隱藏資料夾嗎?
對!lion會隱蔵library,開啟的方法請參考
http://hiraku.tw/2011/07/2685/
等等!剛那方法不太好,如果你不想永久開啟的話,看這個
http://maciku.blogspot.com/2011/07/mac-os-x-107-lion-library.html
感謝你老大,解決了,我要讓他永遠出現
找到了==那資料夾真的是隱藏的,浪費了一天時間阿,還是覺得window比較好用冏
我是剛入手的.
請問 建立的資料庫要放在document ,
因為我在 macbook terminal中的sqlite3 , 建立了一個 db, 是如何放在docuement ?
是否我的app上, 寫一個程式把db 複製入去嗎 ? 只執行一次?
Thanks
你答對了~
版主阿,這樣就換我有疑問了,資料庫找不到時不是會自己建立嗎?既然自己建立了那我還需要複製嗎?
哦~因為我猜John是先建好一個database和table,所以直接複製過去比較快,這樣該有的就都有了,不用再用程式create table
(現在這裡是FMDB討論版了嗎 XD)
不好意思, 還有幾個問題, 想請問你,謝謝你了。
1. 資料庫放在Document, Document 是指 Finder 中見到的“文件” 嗎?,還是 Iphone 上嗎?
2. iPhone模擬器的 Document, 可以用Finder 進入嗎 ?
3. 是否把 sqlite 建立的db, 插入xcode project 任一地方, 再用以下代碼放在viewDidLoad 執行, 用作複製 db 到 iphone 的 Document 中?
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [paths objectAtIndex:0];
NSString *dbPath = [documentsPath stringByAppendingPathComponent:@”demo”];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath: dbPath])
{
NSString *bundle = [[ NSBundle mainBundle] pathForResource:@”demo” ofType:@””];
[fileManager copyItemAtPath:bundle toPath:dbPath error:error];
NSLog(@”YES”);
}
else
{ NSLog(@”NO”);}
4.即是每次開啟app 時, 都要查詢db 是否存在, 不存在才複製嗎?
5.放到 app store 時, 方法和路徑是否不需要修改? 自動會把db放入真機的 Document 嗎?
6. 我用以下sqlite 代碼直接在程式中建立的 db, table , 在那裹可以看到真的存在?
// Get the documents directory
dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
// Build the path to the database file
databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: @”contacts.db”]];
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: databasePath ] == NO)
{
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
char *errMsg;
const char *sql_stmt = “CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)”;
if (sqlite3_exec(contactDB, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
status.text = @”Failed to create table”;
}
sqlite3_close(contactDB);
} else {
status.text = @”Failed to open/create database”;
}
}
1.你在模擬器run,在finder找;你在實機run,去機器找。
2.請爬文 XD(之前有人問過了)
3.是
4.是
5.是
6.(請合併解答1+2)
謝謝你的回覆,
我已經在模擬器的 Document 找到 db.
使用FMDB, 語法真係簡單了. 但如果不使用FMDB, 問題應該都不大嗎?
因為平常只是使用 select , insert , update.
每次只要按照固定的方法修改 sql stmt , 就可以了,
我的想法正確嗎? 因為我不知道FMDB還有其他更好的方法 ?
– (void) saveData
{
sqlite3_stmt *statement;
const char *dbpath = [databasePath UTF8String];
if (sqlite3_open(dbpath, &contactDB) == SQLITE_OK)
{
NSString *insertSQL = [NSString stringWithFormat: @”INSERT INTO CONTACTS (name, address, phone) VALUES (\”%@\”, \”%@\”, \”%@\”)”, name.text, address.text, phone.text];
const char *insert_stmt = [insertSQL UTF8String];
sqlite3_prepare_v2(contactDB, insert_stmt, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_DONE)
{
status.text = @”Contact added”;
name.text = @””;
address.text = @””;
phone.text = @””;
} else {
status.text = @”Failed to add contact”;
}
sqlite3_finalize(statement);
sqlite3_close(contactDB);
}
}
您好 我想問 要如何把fmdb的資料 .db檔 讀取出來 並儲存到NSMutableArray 裡
並且每當資料有新增 或刪除 nsmutablearray也會跟著變動
希望您可以幫幫忙
我剛好也有跟樓上一樣的問題
想要把FMDB建好的table用uitableview顯示出來
不過不知道要怎麼把資料先使用一個array存起來
希望大大可以幫忙一下
請參考“取得資料“那個項目。
SQL跟Objective-C是兩回事,所以只能自己手動把資料全部拉出來,再自己轉成你要用的物件(或者用NSDictionary)才存成array。
希望資料更新時,array也跟著變動,那也是自己手動。我想不到更好的辦法了。有的話還請高手指教。
真的嫌麻煩,Core Data是你的好朋友。(不過好像更麻煩 XD)
不知道您可不可以給個例子
我不知道要怎麼在取得資料那裡 把我的值轉成nsdictionary
希望您可以教一下 困擾很久了呢….
謝謝 我解決了~
不過又衍生出一個問題
當我要更改資料時
我要怎麼更改
像我現在有10比資料的話
我可能要改第5筆 那我要如何改呢?
您好,我转载了您的文章,因为国内要翻墙才能看到,blog中已经帖出了原文地址,地址在http://www.sudobeta.com/mac_os%20/200
讚!
正在煩惱現有的資料還要轉 CoreData 我會煩死
請問一下我想要把從sqlite取出的值存成陣列該如何做呢@@?要怎麼從 NSResultset抓出的直宣告過去呢??
沒有什麼簡單的方法,只能一個個拉出來塞進去。
while ([rs next]) {
NSString *name = [rs stringForColumn:@”Name”];
int age = [rs intForColumn:@”Age”];
// 在這裡存進NSMutableArray裡
}
謝謝版主喔!!!我找到方法了
跟上面應該差不多 我是用addobject一個一個加進去!!
附帶提問一下版主alertview如果加入textfield
在透過另外一個函式驗證button (Switch這裡)
因為兩個是不同的區域
如何將textfield的值傳到button的函式裡頭呢???
不知道版主有沒有涉獵這個部分@@!!
不好意思,有點不太懂你的意思,可否詳細說明?