FMDB有FMDatabase、FMDatabaseQueue、FMResultSet這三個(gè)重量級(jí)的類(lèi)。
- FMDatabase
用來(lái)表示sqlite3數(shù)據(jù)庫(kù)對(duì)象。 - FMDatabaseQueue
用來(lái)執(zhí)行線程安全的多線程數(shù)據(jù)庫(kù)操作。 - FMResultSet
數(shù)據(jù)庫(kù)對(duì)象根據(jù)sql語(yǔ)句進(jìn)行操作后返回的結(jié)果集對(duì)象。
筆者對(duì)于FMDB源碼的探究首先從這三個(gè)類(lèi)入手,由于FMDatabaseQueue引用到了FMDatabase,而FMDatabase又引用到了FMResultSet。所以筆者決定通過(guò)FMResultSet -> FMDatabase -> FMDatabaseQueue這樣的順序來(lái)解讀這三個(gè)類(lèi)。
FMDB中用到的宏
在解讀源碼之前,我們先來(lái)看一下FMDB中常用到的一些宏。
-
NS_ASSUME_NONNULL_BEGIN&NS_ASSUME_NONNULL_END
在代碼中,包含在這兩個(gè)宏中間的屬性、方法均會(huì)被加上一個(gè)nonnull的標(biāo)記。如果想要其中的屬性或方法不受此約束,則在對(duì)應(yīng)的屬性中加入nullable即可
我們可以點(diǎn)擊看到這兩條宏所定義的語(yǔ)句為
#ifndef NS_ASSUME_NONNULL_BEGIN
#define NS_ASSUME_NONNULL_BEGIN _Pragma("clang assume_nonnull begin")
#endif
#ifndef NS_ASSUME_NONNULL_END
#define NS_ASSUME_NONNULL_END _Pragma("clang assume_nonnull end")
#endif
_Pragma看上去是不是很熟悉,我們經(jīng)常在代碼中寫(xiě)
#pragma mark - 自定義字符串
這是C++中的雜注指令,關(guān)于這點(diǎn),可以看看這里。
這意味著,我們這樣寫(xiě)也是有效的
#pragma clang assume_nonnull begin
#pragma clang assume_nonnull end
-
FMDB_SQLITE_STANDALONE
這個(gè)宏是在FMDB中的podspec中定義的
s.subspec 'standalone' do |ss|
ss.xcconfig = { 'OTHER_CFLAGS' => '$(inherited) -DFMDB_SQLITE_STANDALONE' }
ss.dependency 'sqlite3'
ss.source_files = 'src/fmdb/FM*.{h,m}'
ss.exclude_files = 'src/fmdb.m'
end
目前FMDB中設(shè)定的默認(rèn)子文件夾是'standard',并不是standalone或者standalone-fts。所以這個(gè)宏在工程中都返回NO。
-
OS_OBJECT_USE_OBJC
這個(gè)宏在FMDB中用于
#if OS_OBJECT_USE_OBJC
#define FMDBDispatchQueueRelease(__v)
#else
#define FMDBDispatchQueueRelease(__v) (dispatch_release(__v));
#endif
OS_OBJECT_USE_OBJC是針對(duì)過(guò)去iOS 6.0以下版本的GCD并不具備ARC所產(chǎn)生的。所以當(dāng)OS_OBJECT_USE_OBJC返回0時(shí),GCD需要使用dispatch_release()來(lái)釋放內(nèi)存。
-
NS_RETURNS_NOT_RETAINED
這個(gè)宏用于標(biāo)注帶返回值的方法,并且還有一個(gè)兄弟叫做NS_RETURNS_RETAINED。在FMDB中只有2個(gè)方法標(biāo)注了這個(gè)宏,并且都在注釋中寫(xiě)上了Warning。
- (NSData * _Nullable)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED;
- (NSData * _Nullable)dataNoCopyForColumnIndex:(int)columnIdx NS_RETURNS_NOT_RETAINED;
NS_RETURNS_NOT_RETAINED表示這個(gè)方法返回的對(duì)象,不需要被release,而NS_RETURNS_RETAINED則表示方法所返回的對(duì)象需要被release。
最后在提一下__has_feature這個(gè)方法,在Clang中是這么解釋的
HasFeature - Return true if we recognize and implement the feature specified by the identifier as a standard language feature.
即為:如果我們識(shí)別并實(shí)現(xiàn)標(biāo)識(shí)符指定的功能作為標(biāo)準(zhǔn)語(yǔ)言功能,則返回true(google翻譯,doge)。
在Clang中它定義了非常多的關(guān)鍵詞,有興趣的朋友可以去看看PPMacroExpansion.cpp,從1094行開(kāi)始。
再貼一下FMDB中所使用的Sqlite3錯(cuò)誤碼
#define SQLITE_OK 0 /* 成功 | Successful result */
/* 錯(cuò)誤碼開(kāi)始 */
#define SQLITE_ERROR 1 /* SQL錯(cuò)誤 或 丟失數(shù)據(jù)庫(kù) | SQL error or missing database */
#define SQLITE_INTERNAL 2 /* SQLite 內(nèi)部邏輯錯(cuò)誤 | Internal logic error in SQLite */
#define SQLITE_PERM 3 /* 拒絕訪問(wèn) | Access permission denied */
#define SQLITE_ABORT 4 /* 回調(diào)函數(shù)請(qǐng)求取消操作 | Callback routine requested an abort */
#define SQLITE_BUSY 5 /* 數(shù)據(jù)庫(kù)文件被鎖定 | The database file is locked */
#define SQLITE_LOCKED 6 /* 數(shù)據(jù)庫(kù)中的一個(gè)表被鎖定 | A table in the database is locked */
#define SQLITE_NOMEM 7 /* 某次 malloc() 函數(shù)調(diào)用失敗 | A malloc() failed */
#define SQLITE_READONLY 8 /* 嘗試寫(xiě)入一個(gè)只讀數(shù)據(jù)庫(kù) | Attempt to write a readonly database */
#define SQLITE_INTERRUPT 9 /* 操作被 sqlite3_interupt() 函數(shù)中斷 | Operation terminated by sqlite3_interrupt() */
#define SQLITE_IOERR 10 /* 發(fā)生某些磁盤(pán) I/O 錯(cuò)誤 | Some kind of disk I/O error occurred */
#define SQLITE_CORRUPT 11 /* 數(shù)據(jù)庫(kù)磁盤(pán)映像不正確 | The database disk image is malformed */
#define SQLITE_NOTFOUND 12 /* sqlite3_file_control() 中出現(xiàn)未知操作數(shù) | Unknown opcode in sqlite3_file_control() */
#define SQLITE_FULL 13 /* 因?yàn)閿?shù)據(jù)庫(kù)滿導(dǎo)致插入失敗 | Insertion failed because database is full */
#define SQLITE_CANTOPEN 14 /* 無(wú)法打開(kāi)數(shù)據(jù)庫(kù)文件 | Unable to open the database file */
#define SQLITE_PROTOCOL 15 /* 數(shù)據(jù)庫(kù)鎖定協(xié)議錯(cuò)誤 | Database lock protocol error */
#define SQLITE_EMPTY 16 /* 數(shù)據(jù)庫(kù)為空 | Database is empty */
#define SQLITE_SCHEMA 17 /* 數(shù)據(jù)結(jié)構(gòu)發(fā)生改變 | The database schema changed */
#define SQLITE_TOOBIG 18 /* 字符串或二進(jìn)制數(shù)據(jù)超過(guò)大小限制 | String or BLOB exceeds size limit */
#define SQLITE_CONSTRAINT 19 /* 由于約束違例而取消 | Abort due to constraint violation */
#define SQLITE_MISMATCH 20 /* 數(shù)據(jù)類(lèi)型不匹配 | Data type mismatch */
#define SQLITE_MISUSE 21 /* 不正確的庫(kù)使用 | Library used incorrectly */
#define SQLITE_NOLFS 22 /* 使用了操作系統(tǒng)不支持的功能 | Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* 授權(quán)失敗 | Authorization denied */
#define SQLITE_FORMAT 24 /* 附加數(shù)據(jù)庫(kù)格式錯(cuò)誤 | Auxiliary database format error */
#define SQLITE_RANGE 25 /* 傳遞給sqlite3_bind()的第二個(gè)參數(shù)超出范圍 | 2nd parameter to sqlite3_bind out of range */
#define SQLITE_NOTADB 26 /* 被打開(kāi)的文件不是一個(gè)數(shù)據(jù)庫(kù)文件 | File opened that is not a database file */
#define SQLITE_ROW 100 /* sqlite3_step() 已經(jīng)產(chǎn)生一個(gè)行結(jié)果 | sqlite3_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite3_step() 完成執(zhí)行操作 | sqlite3_step() has finished executing */
下一篇我們將走進(jìn)FMResultSet中的世界,一探究竟。