代码之家  ›  专栏  ›  技术社区  ›  Shreesha Kedlaya

如何使realmswift realmopnational与swift codable兼容?

  •  5
  • Shreesha Kedlaya  · 技术社区  · 6 年前

    我面临一个问题,我无法使realmopnational与swift新的可编码特性与json解码器兼容。

    cosider下面的realm对象。

    class School: Object, Codable {
    
        @objc dynamic var id: Int64 = 0
    
        @objc dynamic var name: String?
        var numberOfStudents = RealmOptional<Int64>()
        var classes = List<Class>()
    
        enum CodingKeys: String, CodingKey {
           case id
           case name
           case numberOfStudents
           case classes
        }
    }
    
    class Class: Object, Codable {
        var name: String?
        var numberOfStudents = RealmOptional<Int64>()
    }
    

    在这里,我们可以声明这个类是可编码的,因为我在 this gist 是的。但问题是解码器何时解码json。

    考虑一下这个json

    let jsonData = """
    [
        "id": 1234,
        "name": "Shreesha",
        "numberOfStudents": nil,
        "classes": {
           "name": "Class V",
           "numberOfStudents": 12
        }
    ]
    """.data(using: .utf8)!
    

    在这个json中,所有的数据都被传递,并且与代码完美地解码。

    let decoder = JSONDecoder()
    
    let decoded = try! decoder.decode(School.self, from: jsonData)
    

    但如果我移除 numberOfStudents 来自json数据的键,它应该是realmoptional对象,它将抛出一个错误并且不会解码,因为realmoptional不是swift可选的,所以解码器认为json数据中应该有一个键。在 JSONDecoder 如果json中没有密钥并且属性声明为可选,则它不会尝试解码。它只是跳到其他键。

    直到现在我才重写初始化器,因为我们有 RealmOptional 领域 Lists 等等,但现在我必须超越 init(from decoder: Decoder) 手动解码,领域模型有 50个 它的属性(你知道我的意思)。

    如果我们重写初始化程序,我觉得没有必要使用 J编码器 因为手动操作比使用jsondecoder要多。

    required convenience init(from decoder: Decoder) throws {
        self.init()
        let container = try decoder.container(keyedBy: CodingKeys.self)
    
        id = try container.decodeIfPresent(Int64.self, forKey: .id) ?? 0
        name = try container.decodeIfPresent(String?.self, forKey: .name) ?? ""
        numberOfStudents = try container.decodeIfPresent(RealmOptional<Int64>.self, forKey: .numberOfStudents) ?? RealmOptional<Int64>()
    
        let classesArray = try container.decode([Class].self, forKey: .classes)
        classes.append(objectsIn: classesArray)
    }
    

    所以有人能给我推荐另一种解决方案使现实与 J编码器 所以我们不必重写初始化器。

    3 回复  |  直到 6 年前
        1
  •  3
  •   Sandeep    6 年前

    你可以做些什么来解决这个问题。创建一个新的类,该类支持解码并具有realmoptional属性。

    class OptionalInt64: Object, Decodable {
        private var numeric = RealmOptional<Int64>()
    
        required public convenience init(from decoder: Decoder) throws {
            self.init()
    
            let singleValueContainer = try decoder.singleValueContainer()
            if singleValueContainer.decodeNil() == false {
                let value = try singleValueContainer.decode(Int64.self)
                numeric = RealmOptional(value)
            }
        }
    
        var value: Int64? {
            return numeric.value
        }
    
        var zeroOrValue: Int64 {
            return numeric.value ?? 0
        }
    }
    

    然后,不要在学校课堂上使用realmopational,而是使用这个新的optionalint64类,

    class School: Object, Codable {
    
        @objc dynamic var id: Int64 = 0
    
        @objc dynamic var name: String?
        @objc dynamic  var numberOfStudents: OptionalInt64?
        var classes = List<Class>()
    
        enum CodingKeys: String, CodingKey {
           case id
           case name
           case numberOfStudents
           case classes
        }
    }
    

    注意,现在不是使用realmonial,而是使用realmnumeric?属于可选类型。因为它是可选的,所以自动解码使用decodeifpresent方法来解码可选值。如果json中不存在该值,则该值将变为零。

        2
  •  1
  •   Swaroop S    6 年前
    1. 在realm模型类之上添加@objcmembers。

    2. 使用变量如下

    public dynamic var someValue = RealmOptional<Int>()
    1. 在将值分配给领域(可选)时,可以使用somevalue.value=10

    默认情况下,somevalue为零。

        3
  •  0
  •   Tom Daniel    6 年前

    我发现 this 解决方案和它的工作就像一个魅力。我正在使用srv7的更新代码 comment 是的。