iOS--FMDB v2.6.2

FMDB v2.6.2

這是個SQLite的OC封裝。SQLite的地址:http://sqlite.org/

FMDB郵件名單

http://groups.google.com/group/fmdb

閱讀SQLite的常見問題

http://www.sqlite.org/faq.html

由于FMDB建立在SQLite之上,你想要至上而下讀一遍這個頁面。當(dāng)你在這里,確保你標(biāo)記了SQLite的文檔頁面:http://www.sqlite.org/docs.html

特約Contributing

關(guān)于FMBDB你是不是有什么驚奇的點子呢?你應(yīng)該考慮聯(lián)系ccgus,不過你得確定他并沒有因為一些理由限定了這個點子。另外,pull是隨意的,保持你本地編程的習(xí)慣。然而,即使幾個禮拜也沒有收到來自ccgus的任何訊息也別著急,你可以發(fā)個消息問一下發(fā)生了什么。

CocoaPods

FMDB支持CocoaPods做依賴管理。

如果需要數(shù)據(jù)可加密你需要使用FMDB/SQLCipher.FMDB/SQLCipher聲明了SQLCipher的依賴,允許FMDB通過“-DSQLITE_HAS_CODEC”標(biāo)志去編譯。

FMDB類參考

http://ccgus.github.io/fmdb/html/index.html

ARC還是手動內(nèi)存管理

你可以選擇兩種中任意一種方式,在你的cocoa項目中,F(xiàn)MDB可以在編譯時候跟據(jù)你的選擇編譯正確的code。

用法

FMDB中有三個主要的類

1.FMDatabase-代表一個獨(dú)立的SQLite數(shù)據(jù)庫,執(zhí)行SQL語句。

2.FMResultSet-代表FMDatebase查詢的結(jié)果集

3.FMDatabaseQueue-如果你想要在多線程中查詢和更新,你應(yīng)該使用這個類,

創(chuàng)建數(shù)據(jù)庫

FMDatabase通過一個SQLite數(shù)據(jù)庫文件的路徑創(chuàng)建。這個路徑可以有以下三種樣式:

1.一個系統(tǒng)文件路徑.硬盤上之前不存在的,如果它不存在,F(xiàn)MDB會為你新建。

2.一個空字符串,一個空數(shù)據(jù)庫在臨時文件中創(chuàng)建。在數(shù)據(jù)庫連接關(guān)閉的時候,這個數(shù)據(jù)庫會被刪除。

3.NULL(空)。一個在內(nèi)存中的數(shù)據(jù)庫將被創(chuàng)建。在數(shù)據(jù)庫連接關(guān)閉的時候,這個數(shù)據(jù)庫會被銷毀。

想了解更多關(guān)于臨時或內(nèi)存數(shù)據(jù)庫,請閱讀sqlite文檔:http://www.sqlite.org/inmemorydb.html

eg: FMDatabase *db = [FMDatabase databaseWithpath:@“/tmp/tmp.db”];

打開數(shù)據(jù)庫

和數(shù)據(jù)庫建立連接之前,應(yīng)該確保它是打開的,在內(nèi)存不足、禁止開啟、創(chuàng)建數(shù)據(jù)庫的時候會打開失敗。

if(![db open]){

[db release];

return;

}

執(zhí)行更新

除了SELECT格式的數(shù)據(jù)庫執(zhí)行語句都是更新。包括CREATE,UPDATE,INSERT,ALTER,COMMIT,BEGIN,DETACH,DELETE,DROP,END,EXPLAIN,VACUUM,還有replace語句等等。基本上,只要你的SQL語句不是以SELECT開頭,都是更新語句。

執(zhí)行更新返回一個單一BOOL值,返回值為YES代表執(zhí)行更新成功,返回值為NO表示發(fā)生了一些錯誤。你可以調(diào)用-laseErrorMessage和-laseErrorCode方法接收更多訊息。

執(zhí)行查詢

一個SELECt語句是一個查詢語句并且通過-executrQuery方法執(zhí)行。

執(zhí)行查詢成功返回FMResultSet對象,失敗返回nil。你應(yīng)該使用-laseErrorMessage和-laseErrorCode方法確定到底為什么查詢失敗。

為了循環(huán)訪問查詢結(jié)果集,你可以使用while()循環(huán).你也需要從一個紀(jì)錄到另一條。在FMDB中,最簡單的辦法是這樣:

FMResultSet *s = [db executeQuery:@“SELECT *FROM myTable”];

while ([s next]){

//retrieve values for each record

}

通常你在使用查詢結(jié)果的返回值前必須先調(diào)用-[FMResultSet next],即使你只需要一次,像這樣:

FMResultSet *s = [db executeQuery:@“SELECT COUNT(*) FROM myTable”];

if ([s next]) {

int totalCount = [s intForColumnIndex:0];

}

FMResultSet 擁有許多方法去獲取適當(dāng)類型的數(shù)據(jù)

intForColumn:

longForColumn:

longLongIntForColumn:

boolForColumn:

doubleForColumn:

stringForColumn:

dateForColumn:

dataForColumn:

dataNoCopyForColumn:

UTF8StringForColumnName:

objectForColumnName:

這里的每一個方法都有一個對應(yīng)的{type}ForColumnIndex:表達(dá)式。基于字段在結(jié)果集中的位置可以被用來獲取數(shù)據(jù)

,和字段名一一對應(yīng)。

特別的,你在這里不需要-close一個FMResultSet,直到結(jié)果集都被釋放或者父數(shù)據(jù)庫關(guān)閉了。

關(guān)閉(Closing)

當(dāng)你完成了數(shù)據(jù)的查詢和更新,你應(yīng)該-close這個FMDatabase的連接讓SQLite釋放那些操作過程中占用的資源。

[db close];

Transactions(事務(wù))

FMDatabase可以通過調(diào)用合適的方法或者執(zhí)行開始和結(jié)束事務(wù)型語句開始并提交一個事務(wù)。

多條語句和批量添加

你可以使用FMDatabase的executeStatements:withResultBlock:去做一個多條SQL語句在一個字符串中:

NSString *sql = @"create table bulktest1 (id integer primary key autoincrement, x text);"

"create table bulktest2 (id integer primary key autoincrement, y text);"

"create table bulktest3 (id integer primary key autoincrement, z text);"

"insert into bulktest1 (x) values ('XXX');"

"insert into bulktest2 (y) values ('YYY');"

"insert into bulktest3 (z) values ('ZZZ');";

success = [db executeStatements:sql];

sql = @"select count(*) as count from bulktest1;"

"select count(*) as count from bulktest2;"

"select count(*) as count from bulktest3;";

success = [self.db executeStatements:sql withResultBlock:^int(NSDictionary *dictionary) {

NSInteger count = [dictionary[@"count"] integerValue];

XCTAssertEqual(count, 1, @"expected one record for dictionary %@", dictionary);

return 0;

}];

數(shù)據(jù)處理

當(dāng)提供一個SQL語句到FMDB。你應(yīng)該檢查每一個輸入值.代替的,你可以使用標(biāo)準(zhǔn)綁定語法:

INSERT INTO myTable VALUES (?, ?, ?, ?)

?符號在SQLite標(biāo)準(zhǔn)中是一個插入的占位符。執(zhí)行方法全部的接受來自參數(shù)的變量值(或者是這些參數(shù)的,像NSArray,NSDictionary,或者是va_list),適當(dāng)對你隱藏。

還有,在OC中使用使用?占位符就像這樣:

NSInteger identifier = 42;

NSString *name = @"Liam O'Flaherty (\"the famous Irish author\")";

NSDate *date = [NSDate date];

NSString *comment = nil;

BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", @(identifier), name, date, comment ?: [NSNull null]];

if (!success) {

NSLog(@"error = %@", [db lastErrorMessage]);

}

注意:基本數(shù)據(jù)類型,像NSInteger這樣的變量自負(fù),應(yīng)該用MNSNumber對象表示,需要用@語法,像上面那樣。或者用[NSNumber numberWithInt:identifier]語法也可以。

另外,在SQL中NULL值應(yīng)該用[NSNull null]插入.舉個例子,像上面那個comment自斷可能為nil,你可以一使用comment ?: [NSNull null]語法,當(dāng)comment為不為空是插入這個字符串,為空時插入[NSNull null].

在swift中,你應(yīng)該使用executeUpdate(values:),不僅僅是swift的簡明語法,也同樣是swift2的錯誤拋出句柄。

do {

let identifier = 42

let name = "Liam O'Flaherty (\"the famous Irish author\")"

let date = NSDate()

let comment: String? = nil

try db.executeUpdate("INSERT INTO authors (identifier, name, date, comment) VALUES (?, ?, ?, ?)", values: [identifier, name, date, comment ?? NSNull()])

} catch {

print("error = \(error)")

}

注意:在swift,你不需要像OC那樣基礎(chǔ)數(shù)字類型的封裝,但是如果你想要插入一個可變字符串,你將需要使用這樣的語法comment ?? NSNull() (i.e.,如果為nil,使用NSNull,否則使用這個字符串)。

二選一,你可以使用named參數(shù)語法。

INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)

這個參數(shù)列表必須以冒號開始,SQLite也支持其它符號,但是內(nèi)部字典的key是以冒號前綴的,你字典里的key不要包含冒號。

NSDictionary *arguments = @{@"identifier": @(identifier), @"name": name, @"date": date, @"comment": comment ?: [NSNull null]};

BOOL success = [db executeUpdate:@"INSERT INTO authors (identifier, name, date, comment) VALUES (:identifier, :name, :date, :comment)" withParameterDictionary:arguments];

if (!success) {

NSLog(@"error = %@", [db lastErrorMessage]);

}

在SQL語句中key應(yīng)該使用NSString的stringWithFormat方法手動插入對應(yīng)的值。那么swift的字符串咋辦?,使用?占位符向數(shù)據(jù)庫插入值(或者在SELECT語句中使用WHERE從句)

使用FMDatabaseQueue 和線程安全

在多線程使用同一個FMDatabase的單例是一個壞主意。通常為每一個線程創(chuàng)建FMDatabase對象都是OK的,千萬不要跨線程使用數(shù)據(jù)庫單例,清楚不要在多線程同時使用。壞的事情終將發(fā)生你將會得到一些閃退,或者一個異常,或者是隕石從天而降砸中了你的mac,這些將會被抱怨。

多線程使用的時候不要實力話單例。

用FMDatabaseQueue替代。實例化一個單例FMDatabaseQueue并且在多線程中使用.這個FMDatabaseQueue對象將通過隊列管理同步執(zhí)行來自多線程的命令。這里是如何使用,第一步,創(chuàng)建你的隊列。

FMDatabaseQueue *queue = [FMDatabaseQueue databaseQueueWithPath:aPath];

然后這樣使用它:

[queue inDatabase:^(FMDatabase *db) {

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];

FMResultSet *rs = [db executeQuery:@"select * from foo"];

while ([rs next]) {

}

}];

簡單的多任務(wù)包裝在一個事務(wù)中key這樣做:

[queue inTransaction:^(FMDatabase *db, BOOL *rollback) {

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @1];

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @2];

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @3];

if (whoopsSomethingWrongHappened) {

*rollback = YES;

return;

}

// etc…

[db executeUpdate:@"INSERT INTO myTable VALUES (?)", @4];

}];

在swift里這樣:

queue.inTransaction { db, rollback in

do {

try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [1])

try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [2])

try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [3])

if whoopsSomethingWrongHappened {

rollback.memory = true

return

}

try db.executeUpdate("INSERT INTO myTable VALUES (?)", values: [4])

} catch {

rollback.memory = true

print(error)

}

}

FMDatabaseQueue將在序列號的隊列(從類名開始)執(zhí)行塊.因此你可以同時調(diào)用在多線程的多FMDatabaseQueue的方法,在順序排到的時候它們將被執(zhí)行。這個方法查詢和更新并不會擠在一起,就不會出問題了。

注意:FMDatabaseQueue的方式是塊形勢的,因此即使你正在塊中,他們也不會跑在其它線程。

通過塊自定義sqlite函數(shù)

你可以做這個,例如:查看main.m里的 -makeFunctionNamed:

swift

你也可以在Swift項目中使用FMDB

如果是這樣,你必須:

1.從FMDB的src文件下拷貝相關(guān)的.m和.h文件到你的項目中。

你可以拷貝所有的文件(最簡單的方式),或者只拷貝你需要的。最基本的你需要FMDatabase和FMResultSet。FMDatabaseAddition提供一些非常方便好用的方法,因此你可能也需要它。如果你要在多線程任務(wù)中使用數(shù)據(jù)庫,F(xiàn)MdatabaseQueue也是非常有用的。如果你選擇不要拷貝所有src文件目錄下的文件,你還需要更新FMDB.h,這是與你項目的唯一連接。

注意,如果你拷貝了所有文件到你的項目中(推薦做法),你可能想要拖動個人文件到你的項目中,不是文件夾,因為如果你拖動文件夾,你將得不到關(guān)于添加橋引頭文件(bridging header)的提示(看下一點)

2.如果你被提示創(chuàng)建橋引頭文件,你應(yīng)該創(chuàng)建它。如果你沒有收到提示且之前并沒有橋引頭文件,你應(yīng)該去添加一個。

更多關(guān)于橋引頭文件,看swift和oc混編( Swift and Objective-C in the Same Project.)

3.在你的橋引頭文件中,添加這一行。

#import "FMDB.h"

4.在try模式下使用executeQuery和executeUpdate的變量表達(dá)式帶上sql和values參數(shù),就像下面的代碼一樣,這些executeQuery和executeUpdate的譯文都會拋出對應(yīng)的異常在swift2中。

如果你按照上面的做了,你可以用FMDatabase寫swift代碼,舉例:

let documents = try! NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)

let fileURL = documents.URLByAppendingPathComponent("test.sqlite")

let database = FMDatabase(path: fileURL.path)

if !database.open() {

print("Unable to open database")

return

}

do {

try database.executeUpdate("create table test(x text, y text, z text)", values: nil)

try database.executeUpdate("insert into test (x, y, z) values (?, ?, ?)", values: ["a", "b", "c"])

try database.executeUpdate("insert into test (x, y, z) values (?, ?, ?)", values: ["e", "f", "g"])

let rs = try database.executeQuery("select x, y, z from test", values: nil)

while rs.next() {

let x = rs.stringForColumn("x")

let y = rs.stringForColumn("y")

let z = rs.stringForColumn("z")

print("x = \(x); y = \(y); z = \(z)")

}

} catch let error as NSError {

print("failed: \(error.localizedDescription)")

}

database.close()

歷史

歷史和變化總結(jié)在GitHub Page的CHANGES_AND_TODO_LIST.txt里可見。

貢獻(xiàn)者

FMDB的貢獻(xiàn)者名單在Contributors.txt”中

在項目中使用FMDB,你應(yīng)該有志于成為一個有辨識力的開發(fā)者

FMDBMigrationManager,一個FMDBSQLite架構(gòu)遷移管理系統(tǒng)

https://github.com/layerhq/FMDBMigrationManager

FCModel,一個對操作SQL易取可選擇的核心數(shù)據(jù)模型。

https://github.com/marcoarment/FCModel

FMDB開源的代碼風(fēng)格

空格,不要tab鍵。方括號,不要打點語法。FMDB的早就在執(zhí)行方括號格式,一直保持這樣的風(fēng)格。

報告bug

編碼時盡量減少bug。你需要讓開發(fā)者很簡單的發(fā)現(xiàn)你的bug并且復(fù)現(xiàn)。如果有用,裝作那個可以有效解決bug的人支持著3個主要項目。為一些開源項目工作,有一個新生的寶寶,通常時候非常非常忙。

我們曾經(jīng)添加模版函數(shù)在main.m(FMDBReportABugFunction)在FMDB發(fā)布版本幫你解決。

通過Xcode打開fmdb項目

打開main.m函數(shù)修改FMDBReportABugFunction重現(xiàn)。

設(shè)置你的表在代碼中。

確認(rèn)你的查詢或者是更新

添加一些關(guān)于這個bug的斷言

然后你可以把這些通過郵件發(fā)給FMDB郵件表。或者,你可以紀(jì)錄這個bug通過githubFMDBbug記錄員。

可選的:

解決這個bug,發(fā)送附件到郵件表,確保所有其它測試在你的修改運(yùn)行之后。

支持

這個FMDB支持通道是一個郵件地址列表(上面有),bug提在這里,或者在Stack Overflow。所以就是說,社區(qū)和志愿組織提供支持。

FMDB開發(fā)是監(jiān)視。如果FMDB對你有幫助,考慮采購一個應(yīng)用FM或者告訴你的朋友關(guān)于它。

執(zhí)照

FMDB的許可證在"License.txt”文件中

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內(nèi)容