摘要:作為微信的終端數(shù)據(jù)庫,從開源至今,共迭代了個版本。微信也轉向開發(fā)了嗎相信這會是大家非常關心的問題。不僅微信,國內(nèi)外大部分都還沒有完全轉向,但顯然這是個趨勢。另一方面,沒有微信的上線機制的保護和龐大的用戶量的驗證,我們需要確保的穩(wěn)定性。
WCDB 作為微信的終端數(shù)據(jù)庫,從 2017.6 開源至今,共迭代了 5 個版本。我們一直關注開發(fā)者們的需求,并不斷優(yōu)化性能,新增如全文搜索等常用的功能。而這其中,呼聲最高的莫過于 對 Swift 的支持。
WCDB ObjC 版本的實現(xiàn)中,由于引入了 C++ 代碼,并不能直接 bridge 到 Swift。因此,我們從 9 月份開始就著手使用原生的 Swift,重寫 WCDB。并于 10.10 和 11.8 分別在開發(fā)者群內(nèi)發(fā)布了 alpha 和 beta 版進行測試。
今天,終于可以正式發(fā)布 WCDB Swift 的第一個正式版本了。
WCDB Swift 約有 1.5w 行代碼,使用 Pure Swift 編寫,幾乎不包含 Cocoa 的代碼。且與 ObjC 版保持完全一致的功能。
模型綁定WCDB Swift 的模型綁定,基于 Swift 4.0 的 Codable 協(xié)議實現(xiàn)。通過建立 Swift 類型與數(shù)據(jù)庫表之間的映射關系,使得開發(fā)者可以通過類對象直接操作數(shù)據(jù)庫。
//Sample.swift class Sample: TableCodable { var identifier: Int? = nil var description: String? = nil var unused: Int? = nil enum CodingKeys: String, CodingTableKey { typealias Root = Sample static let objectRelationalMapping = TableBinding(CodingKeys.self) case identifier case description } } //main.swift let tableName = "sampleTable" try database.create(table: tableName,of: Sample.self) let object = Sample() object.identifier = 1 object.description = "sample_insert" try database.insert(objects: object, intoTable: tableName)語言集成查詢
語言集成查詢深度結合了 Swift 和 SQL 的語法,使得純字符串的 SQL 可以以代碼的形式表達出來。結合代碼提示及糾錯,極大地提高開發(fā)效率。
同時,由于 Swift 的語法 比 Objective-C 更加簡潔,并有更強大的范型和類型推導,使得 WCDB 接口不僅更易編寫,而且更易讀易維護。
let objects: [Sample] = try database.getObjects(fromTable: tableName, where: Sample.Properties.identifier > 0 && Sample.Properties.description.isNotNull())
類似 Sample.Properties.identifier > 0 的語法,其返回值并不為 Bool,而是語言集成查詢的 Expression 對象,WCDB 會根據(jù)這個語句,去進行 SQL 的查詢。同時,通過類型的定義,Swift 即可推導出 WCDB 查詢的結果為 Sample 類。
語言集成查詢同時內(nèi)建了反注入機制,可以避免第三方從輸入框注入 SQL,進行預期之外的惡意操作。深入 SQLite 源碼的性能優(yōu)化
WCDB 基于 SQLite 開發(fā),我們在之前的文章介紹過其對 SQLite 源碼進行的性能優(yōu)化,以適配移動終端的場景。同樣地,這部分優(yōu)化 Swift 版本也能享受到。
線程安全且并發(fā)WCDB Swift 不僅可以安全地在任意線程進行數(shù)據(jù)庫操作,且其內(nèi)部會智能地根據(jù)操作類型調(diào)配資源,使其能夠并發(fā)執(zhí)行,進一步提升效率。
加密基于 SQLCipher 的加密機制,可以為客戶端數(shù)據(jù)安全提供一定程度的保障。
字段升級數(shù)據(jù)庫模型與類定義綁定,使得字段的增加、刪除、修改都與類變量的定義保持一致,不需要開發(fā)者額外地管理字段的版本。
class Sample: TableCodable { var identifier: Int? = nil var description: String? = nil var newColumn: Date? = nil var unused: Int? = nil enum CodingKeys: String, CodingTableKey { typealias Root = Sample static let objectRelationalMapping = TableBinding(CodingKeys.self) case identifier case description case newColumn } } let tableName = "sampleTable" try database.create(table: tableName,of: Sample.self)
模型綁定中新增了 newColumn 字段,該字段也會被自動創(chuàng)建到數(shù)據(jù)庫表中,開發(fā)者不需要手動管理。
全文搜索WCDB Swift 提供簡單易用的全文搜索接口,并包含適配多種語言的分詞器,使得數(shù)據(jù)搜索更精準。
損壞修復內(nèi)建的修復工具可以在系統(tǒng)錯誤、磁盤故障等情況下,盡最大限度地將損壞的數(shù)據(jù)找回并導出。
Pure Swift模型綁定對語言的依賴性很大。由于 ObjC 其強大的消息轉發(fā)機制,使得 WCDB 實現(xiàn)起來并沒有太大的問題。然而,動態(tài)性卻恰恰是 Swift 一直為人詬病的地方。
最省事的解決方案就是,直接引入 Cocoa,所有的問題都將不再是問題。然而,這并不是我們所期望的。
理性分析可以得出,一方面,全面的動態(tài)化會拖累 Swift 的性能,另一方面,這也會使得 Swift 的原生類型難以享受到模型綁定。
但我們的理由可能更感性一些 --- 情懷。稱之為強迫癥也好,代碼潔癖也罷,Swift with Cocoa 總讓人心里有那么一絲別扭。因此,我們決定尋找 Swift 原生的解決方案。
WCDB 的模型綁定對語言有兩點依賴:
Accessor。ObjC 版本使用 selector 的 IMP 指針,使得 WCDB 可以獲取變量的值,并插入到數(shù)據(jù)庫中,或從數(shù)據(jù)庫中獲取數(shù)據(jù)寫入到變量。
數(shù)據(jù)庫字段的映射。ObjC 版本使用宏定義,使得 WCDB 可以通過 className.propertyName 的方式進行語言集成查詢的操作。
KeyPath我們最初盯上的是 Swift 的 KeyPath 的機制,它通過 的語法,可以直接對變量進行讀寫操作,且語法上也與 className.propertyName 類似。
let sample=Sample() sample[keyPath: Sample.identifier] = 1 print(sample[keyPath: Sample.identifier]) // 輸出 1
一個難題是,KeyPath 在不引入 Cocoa 的情況下,是并不提供 property 的名稱,這就無法通過 KeyPath 直接映射數(shù)據(jù)庫的字段。
Swift 也有一個相關的 SR 在討論這個問題。
顯然,我們不可能等待這個特性實現(xiàn)了再去做 WCDB Swift。因此我們嘗試使用“不常規(guī)”的方法,獲取到 KeyPath 對應的 property 名稱。
Mirror 是 Swift 里的反射類型,它可以遍歷每個變量,獲取其名稱和值,但不能對變量寫入數(shù)據(jù)。因此我們可以通過 KeyPath 對變量設一個獨一無二的特征值,然后再通過 Mirror 遍歷變量,導出與特征值相同的 property 名稱。
sample[keyPath: Sample.identifier] = 0x539D7C2 // 不易沖突的特征值 let mirror = Mirror(reflecting: sample) for child in mirror.children { if child.value == 0x539D7C2 { print(child.label) break } }
這個“不常規(guī)”的用法在大部分情況下能夠生效,但對于 class 和 struct 相互嵌套的變量,容易因為內(nèi)存混亂導致 crash。
Codable在 KeyPath 的方案不夠完善的情況下,我們轉投了 Codable 協(xié)議。它是 Swift 4.0 新增的特性,本質是編譯前根據(jù)定義生成代碼,以完成序列化和反序列化的任務。
// Swift 官方文檔中的 Codable 示例 struct Landmark: Codable { var name: String var foundingYear: Int var location: Coordinate var vantagePoints: [Coordinate] enum CodingKeys: String, CodingKey { case name = "title" case foundingYear = "founding_date" case location case vantagePoints } } let data = try JSONEncoder().encode(landmark)
對應到 WCDB,將數(shù)據(jù)庫的字段讀寫到變量中,其本質就是一個序列化和反序列化的過程,而 CodingKeys 也可能可以用于語言集成查詢中的字段映射。
然而,由于這個特性還很新,還沒有太多文檔對其進行深入介紹,尤其是自定義 Encoder 和 Decoder 這部分。
所幸的是,Swift 本身就是開源的。因此,我們參考 swift-corelibs-foundation 中的 JSONEncoder 和 JSONDecoder,實現(xiàn)了 TableEncoder 和 TableDecoder,并通過 CodingKeys 的定義,映射數(shù)據(jù)庫中的字段。
最終維護了我們對 Pure Swift 的堅持。
class Sample: TableCodable { var identifier: Int? = nil var description: String? = nil var offset: Int = 0 var debugDescription: String? = nil enum CodingKeys: String, CodingTableKey { typealias Root = Sample static let objectRelationalMapping = TableBinding(CodingKeys.self) case identifier = "id" case description case offset = "db_offset" } } let sample: Sample = try database.getObject(fromTable: tableName, where: Sample.Properties.identifier==1)微信也轉向 Swift 開發(fā)了嗎?
相信這會是大家非常關心的問題。然而,很遺憾,目前還沒有。不僅微信,國內(nèi)外大部分 app 都還沒有完全轉向 Swift,但顯然這是個趨勢。
Google 在 11 月 fork 了 Swift。
大家猶豫不定的原因都大同小異:ABI 不穩(wěn)定,需要將二進制打包進去,增大 app 體積;某些方面性能還不夠好,而且現(xiàn)在多數(shù)是與 ObjC 混編,將進一步拉低性能 等等。
而這其中一個很重要的原因就是,Swift 的基礎設施還不完善,還難以支撐其大型 app 的開發(fā)。而 WCDB Swift 就是這類基礎設施之一。
因此,先有 WCDB Swift,未來才有用 Swift 編寫微信的可能,這邏輯沒毛病。
另一方面,沒有微信的上線機制的保護和龐大的用戶量的驗證,我們需要確保 WCDB Swift 的穩(wěn)定性。因此,在 WCDB Swift 的第一版本,我們就提供了相對完善的測試用例,用例的代碼覆蓋率為 91.34%,能夠觸達絕大部分使用場景。
更多 WCDB Swift 的教程文檔、代碼樣例,包括源碼,都直接到 Github 的 Tencent/wcdb 了解。
我們一起期待 Swift 成為開發(fā)者的首選的那一天。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/17674.html
摘要:本文即以簡單的回歸擬合為例,從最基礎的庫安裝數(shù)據(jù)導入數(shù)據(jù)預處理到模型訓練模型預測介紹了如何使用進行簡單的機器學習任務。 前端每周清單第 18 期:Firefox、Chrome、React、Angular發(fā)布新版本;提升RN應用性能的方法 為InfoQ中文站特供稿件,首發(fā)地址為這里;如需轉載,請與InfoQ中文站聯(lián)系。從屬于筆者的 Web 前端入門與工程實踐的前端每周清單系列系列;部分...
閱讀 2528·2021-07-26 23:38
閱讀 3430·2019-08-30 13:10
閱讀 2315·2019-08-29 18:33
閱讀 2320·2019-08-29 16:12
閱讀 987·2019-08-29 10:59
閱讀 1797·2019-08-26 17:40
閱讀 765·2019-08-26 11:59
閱讀 811·2019-08-26 11:41