我面临一个问题,我无法通过json解码器使RealmOptional与
swift新的Codable功能兼容.
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>()
}
在这里我们可以将类声明为Codable,因为我在this gist的帮助下为RealmOptinal编写了一个扩展.但问题是当解码器解码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)
但是如果我从应该是RealmOptional对象的json数据中删除numberOfStudents键,它将抛出一个错误并且它不会解码因为RealmOptional不是一个快速可选的,所以解码器认为json数据中应该有一个键.在JSONDecoder中,它不会尝试解码,如果json中没有键,并且属性被声明为可选.它只是跳到其他键.
到目前为止,我没有覆盖初始化器,因为我们拥有RealmOptional Realm Lists等的所有支持扩展.但是现在我必须覆盖init(来自解码器:解码器)以手动解码它并且Realm模型具有50多个属性它(你知道我的意思).
如果我们覆盖初始化器,我觉得使用JSONDecoder没有意义,因为手动工作比使用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)
}
因此,有人可以建议我使用替代解决方案使RealmOptional与JSONDecoder兼容,这样我们就不必覆盖初始化器.
最佳答案 您可以采取以下措施来解决问题.创建一个支持解码的新类,并将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
}
}
然后,不要在学校班级中使用RealmOptional,而是使用这个新的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
}
}
请注意,现在使用RealmNumeric而不是使用RealmOptional?其类型为Optional.由于它是可选的,因此自动解码使用decodeIfPresent方法来解码可选值.如果它不存在于json中,则该值将变为零.