Skip to content

Swift 自定义字段映射类型

Qiuwen-chen edited this page Mar 28, 2023 · 8 revisions

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

class MyClass {
	var variable1: String = ""
	var variable2: String = ""
}

class Sample: TableCodable {
    var myClass: MyClass? = nil // 编译错误,myClass 无法进行字段映射
    
    enum CodingKeys: String, CodingTableKey {
        typealias Root = Sample
        static let objectRelationalMapping = TableBinding(CodingKeys.self)
        case myClass
    }
}

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

ColumnCodable

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

public protocol ColumnCodableBase {
    static var columnType: ColumnType {get}
}

public protocol ColumnEncodable: Encodable, ColumnCodableBase {
    func archivedValue() -> FundamentalValue // 将该类型转换为基础类型
}

public protocol ColumnDecodable: Decodable, ColumnCodableBase {
    init?(with value: FundamentalValue) // 将基础类型转换为该类型
}

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

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

// 错误示例,请勿参照
class MyClass: ColumnCodable {
    var variable1: String
    var variable2: String

    static var columnType: ColumnType {
        return .BLOB
    }

    required init?(with value: FundamentalValue) {
        let data = value.dataValue
        guard data.count > 0 else {
            return nil
        }
        guard let dictionary = try? JSONDecoder().decode([String: String].self, from: data) else {
            return nil
        }
        variable1 = dictionary["variable1"] as? String ?? ""
        variable2 = dictionary["variable2"] as? String ?? ""
    }

    func archivedValue() -> FundamentalValue {
        guard let data = try? JSONEncoder().encode([
            "variable1": variable1,
            "variable2": variable2]) else {
            return FundamentalValue(data)
        }
        return FundamentalValue(nil)
    }
}

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

class MyClass: ColumnJSONCodable {
	var a: String = ""
	var b: String = ""
}

文件与代码模版

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

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

文件模版

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

在弹出的菜单中依次

  1. 输入文件名
  2. 选择 Language 为 Swift
  3. 选择对应的基础类型

ColumnCodableXctemplate

代码模版

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

ColumnCodableSnippet

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

Clone this wiki locally