FMDB源碼系列(一)

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中的世界,一探究竟。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容