微信終端開發團隊:新年新語言,WCDB Swift

歡迎你們前往雲+社區,獲取更多騰訊海量技術實踐乾貨哦~
數據庫

做者:sanhuazhang,此文發佈在微信終端開發團隊的專欄小程序

WCDB 做爲微信的終端數據庫,從 2017.6 開源至今,共迭代了 5 個版本。咱們一直關注開發者們的需求,並不斷優化性能,新增如全文搜索等經常使用的功能。而這其中,呼聲最高的莫過於 對 Swift 的支持。swift

WCDB ObjC 版本的實現中,因爲引入了 C++ 代碼,並不能直接 bridge 到 Swift。所以,咱們從 9 月份開始就着手使用原生的 Swift,重寫 WCDB。並於 10.10 和 11.8 分別在開發者羣內發佈了 alpha 和 beta 版進行測試。微信小程序

今天,終於能夠正式發佈 WCDB Swift 的第一個正式版本了。安全

WCDB Swift 約有 1.5w 行代碼,使用 Pure Swift 編寫,幾乎不包含 Cocoa 的代碼。且與 ObjC 版保持徹底一致的功能。性能優化

模型綁定

WCDB Swift 的模型綁定,基於 Swift 4.0 的 Codable 協議實現。經過創建 Swift 類型與數據庫表之間的映射關係,使得開發者能夠經過類對象直接操做數據庫。微信

語言集成查詢

語言集成查詢深度結合了 Swift 和 SQL 的語法,使得純字符串的 SQL 能夠以代碼的形式表達出來。結合代碼提示及糾錯,極大地提升開發效率。併發

同時,因爲 Swift 的語法 比 Objective-C 更加簡潔,並有更強大的範型和類型推導,使得 WCDB 接口不只更易編寫,並且更易讀易維護。app

相似 Sample.Properties.identifier > 0 的語法,其返回值並不爲 Bool,而是語言集成查詢的 Expression 對象,WCDB 會根據這個語句,去進行 SQL 的查詢。同時,經過類型的定義,Swift 便可推導出 WCDB 查詢的結果爲 Sample 類。ide

語言集成查詢同時內建了反注入機制,能夠避免第三方從輸入框注入 SQL,進行預期以外的惡意操做。

深刻 SQLite 源碼的性能優化

WCDB 基於 SQLite 開發,咱們在以前的文章介紹過其對 SQLite 源碼進行的性能優化,以適配移動終端的場景。一樣地,這部分優化 Swift 版本也能享受到。

線程安全且併發

WCDB Swift 不只能夠安全地在任意線程進行數據庫操做,且其內部會智能地根據操做類型調配資源,使其可以併發執行,進一步提高效率。

加密

基於 SQLCipher 的加密機制,能夠爲客戶端數據安全提供必定程度的保障。

字段升級

數據庫模型與類定義綁定,使得字段的增長、刪除、修改都與類變量的定義保持一致,不須要開發者額外地管理字段的版本。

模型綁定中新增了 newColumn 字段,該字段也會被自動建立到數據庫表中,開發者不須要手動管理。

全文搜索

WCDB Swift 提供簡單易用的全文搜索接口,幷包含適配多種語言的分詞器,使得數據搜索更精準。

損壞修復

內建的修復工具能夠在系統錯誤、磁盤故障等狀況下,盡最大限度地將損壞的數據找回並導出。

Pure Swift

模型綁定對語言的依賴性很大。因爲 ObjC 其強大的消息轉發機制,使得 WCDB 實現起來並無太大的問題。然而,動態性卻偏偏是 Swift 一直爲人詬病的地方。

最省事的解決方案就是,直接引入 Cocoa,全部的問題都將再也不是問題。然而,這並非咱們所指望的。

理性分析能夠得出,一方面,全面的動態化會拖累 Swift 的性能,另外一方面,這也會使得 Swift 的原生類型難以享受到模型綁定。

但咱們的理由可能更感性一些 --- 情懷。稱之爲強迫症也好,代碼潔癖也罷,Swift with Cocoa 總讓人內心有那麼一絲彆扭。所以,咱們決定尋找 Swift 原生的解決方案。

WCDB 的模型綁定對語言有兩點依賴:

1. Accessor。ObjC 版本使用 selectorIMP 指針,使得 WCDB 能夠獲取變量的值,並插入到數據庫中,或從數據庫中獲取數據寫入到變量。

2. 數據庫字段的映射。ObjC 版本使用宏定義,使得 WCDB 能夠經過className.propertyName 的方式進行語言集成查詢的操做。

KeyPath

咱們最初盯上的是 Swift 的 KeyPath 的機制,它經過 \ 的語法,能夠直接對變量進行讀寫操做,且語法上也與 className.propertyName 相似。

一個難題是,KeyPath 在不引入 Cocoa 的狀況下,是並不提供 property 的名稱,這就沒法經過 KeyPath 直接映射數據庫的字段。

Swift 也有一個相關的 SR 在討論這個問題。

顯然,咱們不可能等待這個特性實現了再去作 WCDB Swift。所以咱們嘗試使用「不常規」的方法,獲取到 KeyPath 對應的 property 名稱。

Mirror 是 Swift 裏的反射類型,它能夠遍歷每一個變量,獲取其名稱和值,但不能對變量寫入數據。所以咱們能夠經過 KeyPath 對變量設一個獨一無二的特徵值,而後再經過Mirror 遍歷變量,導出與特徵值相同的 property 名稱。

這個「不常規」的用法在大部分狀況下可以生效,但對於 classstruct 相互嵌套的變量,容易由於內存混亂致使 crash。

Codable

KeyPath 的方案不夠完善的狀況下,咱們轉投了 Codable 協議。它是 Swift 4.0 新增的特性,本質是編譯前根據定義生成代碼,以完成序列化和反序列化的任務。

對應到 WCDB,將數據庫的字段讀寫到變量中,其本質就是一個序列化和反序列化的過程,而 CodingKeys 也可能能夠用於語言集成查詢中的字段映射。

然而,因爲這個特性還很新,尚未太多文檔對其進行深刻介紹,尤爲是自定義 EncoderDecoder 這部分。

所幸的是,Swift 自己就是開源的。所以,咱們參考 swift-corelibs-foundation 中的JSONEncoderJSONDecoder,實現了 TableEncoderTableDecoder,並經過CodingKeys 的定義,映射數據庫中的字段。

最終維護了咱們對 Pure Swift 的堅持。

微信也轉向 Swift 開發了嗎?

相信這會是你們很是關心的問題。然而,很遺憾,目前尚未。不只微信,國內外大部分 app 都尚未徹底轉向Swift,但顯然這是個趨勢。

Google 在 11 月 fork 了 Swift。

你們舉棋不定的緣由都大同小異:ABI不穩定,須要將二進制打包進去,增大app體積;某些方面性能還不夠好,並且如今多數是與 ObjC 混編,將進一步拉低性能 等等。

而這其中一個很重要的緣由就是,Swift 的基礎設施還不完善,還難以支撐其大型 app 的開發。而 WCDB Swift 就是這類基礎設施之一。

所以,先有 WCDB Swift,將來纔有用 Swift 編寫微信的可能,這邏輯沒毛病。

另外一方面,沒有微信的上線機制的保護和龐大的用戶量的驗證,咱們須要確保 WCDB Swift 的穩定性。所以,在 WCDB Swift 的初版本,咱們就提供了相對完善的測試用例,用例的代碼覆蓋率爲 91.34%,可以觸達絕大部分使用場景。

更多 WCDB Swift 的教程文檔、代碼樣例,包括源碼,直接到 Github 的 Tencent/wcdb 瞭解。

咱們一塊兒期待 Swift 成爲開發者的首選的那一天。


相關閱讀

相關文章
相關標籤/搜索