Post

WCDB之常见错误(六)

前言

在使用和测试过程中,遇到过一些报错信息,后续经过一段时间才定位到问题,特记录

问题一

更新try database.update(table:xxx, on:xxx, with:xxx)报错datatype mismatch

[ERROR] Code:Mismatch Source:SQLite,Path:/Users/xxx/Library/Developer/CoreSimulator/Devices/xxxxxx/data/Containers/Data/Application/2D5D2272-C60C-46E7-9DEF-9AF8927F0C53/Library/xxxx/test.sqlite,SQL:UPDATE xxxTable SET aid = ?1, bId = ?2, cName,Message:datatype mismatch

问题二

执行查询语句时let list: [XXX]? = try database?.getObjects(on: xxx,fromTable: xxx, where:xxx)时报

WCDBSwift/Select.swift:131: Assertion failed: Properties must belong to PeopleDBModel.CodingKeys.

原因时查询出来结构化好的模型类似于转换的模型不一致,检查下修改为一致即可

问题三

定义数据库对应的模型时报错

Extension outside of file declaring enum 'XXXX' prevents automatic synthesis of 'encode(to:)' for protocol 'Encodable' Extension outside of file declaring enum 'xxxx' prevents automatic synthesis of 'init(from:)' for protocol 'Decodable'

这是由于定义的枚举类型针对ColumnCodable的扩展与枚举定义不在同一个文件里,增加标准的模板化代码即可

1
2
3
4
5
6
7
8
9
10
11
12
extension XXXX: ColumnCodable {
    // ===start===由于分类与定义不在同一个文件,需要自定decoder\encoder
    init(from decoder: any Decoder) throws {
        let container = try decoder.singleValueContainer()
        let val = try container.decode(RawValue.self)
        self.init(rawValue: val)!
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.rawValue)
    }
}

Type 'XXXX' does not conform to protocol 'ColumnDecodable' Type 'XXXX' does not conform to protocol 'ColumnEncodable' 这是没有实现ColumnCodable协议,写如下代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
extension XXXX: ColumnCodable {
    // ** ColumnCodable -- start **/
    static var columnType: ColumnType {
        return .integer32
    }
    init?(with value: Value) {
        self.init(rawValue: value.intValue)
    }
    func archivedValue() -> Value {
        return Value(self.rawValue)
    }
    // ** ColumnCodable -- end **/
}

完整实现的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
extension XXXX: ColumnCodable {
    // ===start===由于分类与定义不在同一个文件,需要自定decoder\encoder
    init(from decoder: any Decoder) throws {
        let container = try decoder.singleValueContainer()
        let val = try container.decode(RawValue.self)
        self.init(rawValue: val)!
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.rawValue)
    }
    // ===end===由于分类与定义不在同一个文件,需要自定decoder\encoder
    // ** ColumnCodable -- start **/
    static var columnType: ColumnType {
        return .integer32
    }
    init?(with value: Value) {
        self.init(rawValue: value.intValue)
    }
    func archivedValue() -> Value {
        return Value(self.rawValue)
    }
    // ** ColumnCodable -- end **/
}

问题四

结构体或类 structclass实现ColumnJSONCodable时报错

1、Extension outside of file declaring struct 'XXX' prevents automatic synthesis of 'encode(to:)' for protocol 'Encodable' 2、Extension outside of file declaring struct 'XXXX' prevents automatic synthesis of 'init(from:)' for protocol 'Decodable' 3、Extension outside of file declaring class 'XXXX' prevents automatic synthesis of 'encode(to:)' for protocol 'Encodable' 4、Extension outside of file declaring class 'XXXX' prevents automatic synthesis of 'init(from:)' for protocol 'Decodable''

实现如下模板代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// xxx.swift
struct XXXX {
  // 是否好友
  var isFriend: Bool = false
  // 好友备注名
  var remarkName: String = String()

  init() {}
}
// xxx+exts.swift
extension XXXX: ColumnJSONCodable {
    // ** 由于struct的定义,与extension不在同一个文件里才需要 -- start **/
    enum CodingKeys: String, CodingKey {
        case isFriend
        case remarkName
    }
    func encode(to encoder: any Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(isFriend, forKey: .isFriend)
        try container.encode(remarkName, forKey: .remarkName)
    }
    
    init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        isFriend = try container.decode(Bool.self, forKey: .isFriend)
        remarkName = try container.decode(String.self, forKey: .remarkName)
    }
}
This post is licensed under CC BY 4.0 by the author.