在模型绑定一章中,已经介绍了模型绑定及其内建支持的类型。对于不支持的类,则无法进行字段映射。

  1. class MyClass {
  2. var variable1: String = ""
  3. var variable2: String = ""
  4. }
  5.  
  6. class Sample: TableCodable {
  7. var myClass: MyClass? = nil // 编译错误,myClass 无法进行字段映射
  8.  
  9. enum CodingKeys: String, CodingTableKey {
  10. typealias Root = Sample
  11. static let objectRelationalMapping = TableBinding(CodingKeys.self)
  12. case myClass
  13. }
  14. }

而本章将介绍开发者如何进行自定义字段映射类型,同时还将提供文件模版和代码模版以简化定义的操作。

ColumnCodable

自定义类需要支持字段映射并不复杂,只需实现 ColumnCodable 协议皆可。ColumnCodableColumnEncodableColumnDecodable 组成,以下是它们的原型:

  1. public protocol ColumnCodableBase {
  2. static var columnType: ColumnType {get}
  3. }
  4.  
  5. public protocol ColumnEncodable: Encodable, ColumnCodableBase {
  6. func archivedValue() -> FundamentalValue // 将该类型转换为基础类型
  7. }
  8.  
  9. public protocol ColumnDecodable: Decodable, ColumnCodableBase {
  10. init?(with value: FundamentalValue) // 将基础类型转换为该类型
  11. }

FundamentalValue 为该类在数据库中存储的形式。例如,Int 可以以 Int64 的形式存储。Date 既可以以时间戳 Double 的形式存储,也可以以 JSON 序列化后 Data 的形式存储。这需要开发者自行确定。而 archivedValueinit?(with:) 实际上就是序列化和反序列化的过程。

以上述的 MyClass 为例,可以以 JSON 的方式对其进行存储,并支持字段映射。JSON 的输出为 Data,因此其可以实现为:

  1. // 错误示例,请勿参照
  2. class MyClass: ColumnCodable {
  3. var variable1: String
  4. var variable2: String
  5.  
  6. static var columnType: ColumnType {
  7. return .BLOB
  8. }
  9.  
  10. required init?(with value: FundamentalValue) {
  11. let data = value.dataValue
  12. guard data.count > 0 else {
  13. return nil
  14. }
  15. guard let dictionary = try? JSONDecoder().decode([String: String].self, from: data) else {
  16. return nil
  17. }
  18. variable1 = dictionary["variable1"] as? String ?? ""
  19. variable2 = dictionary["variable2"] as? String ?? ""
  20. }
  21.  
  22. func archivedValue() -> FundamentalValue {
  23. guard let data = try? JSONEncoder().encode([
  24. "variable1": variable1,
  25. "variable2": variable2]) else {
  26. return FundamentalValue(data)
  27. }
  28. return FundamentalValue(nil)
  29. }
  30. }

由于 JSON 是比较常用的序列化和反序列化方式,因此 WCDB Swift 基于 Swift 4.0 的 Codable 协议,实现了默认的 ColumnJSONCodable

  1. class MyClass: ColumnJSONCodable {
  2. var a: String = ""
  3. var b: String = ""
  4. }

文件与代码模版

自定义字段映射类型中,有部分是格式固定的代码,因此,WCDB Swift 提供了文件模版和代码模版两种方式,以简化操作。

文件和代码模版都在源代码的 tools/templates 目录下,链入 WCDB Swift 时会自动安装。

文件模版

文件模版安装完成后,在 Xcode 的菜单 File -> New -> File… 中创建新文件,选择 ColumnCodable

在弹出的菜单中依次

  • 输入文件名
  • 选择 Language 为 Swift
  • 选择对应的基础类型
    ColumnCodableXctemplate

代码模版

在代码文件中的任意位置,输入 ColumnCodableClass 后选择对应基础类型的代码模版即可。

ColumnCodableSnippet

文件和代码模版都是以 class 作为例子的,实际上 struct 甚至 enum 都可以作为字段映射的类型。