Shr*_*aya 6 realm swift codable jsondecoder
我面临着一个问题,即我无法使RealmOptional与带有json解码器的快速新Codable功能兼容。
考虑以下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>()
}
Run Code Online (Sandbox Code Playgroud)
在这里我们可以将类声明为Codable,因为我借助此要点为RealmOptinal编写了扩展。但是问题是解码器解码json时。
考虑这个json
let jsonData = """
[
"id": 1234,
"name": "Shreesha",
"numberOfStudents": nil,
"classes": {
"name": "Class V",
"numberOfStudents": 12
}
]
""".data(using: .utf8)!
Run Code Online (Sandbox Code Playgroud)
在这个json中,所有数据都被传递,并且用代码完美地解码。
let decoder = JSONDecoder()
let decoded = try! decoder.decode(School.self, from: jsonData)
Run Code Online (Sandbox Code Playgroud)
但是,如果我numberOfStudents从应该是RealmOptional对象的json数据中删除密钥,则会抛出错误并且不会解码,因为RealmOptional不是快速可选的,因此解码器认为json数据中应该有一个密钥。在JSONDecoder它不尝试解码,如果该键不存在于JSON和属性被声明为可选。它只是跳到其他键。
到现在为止,我没有覆盖初始化器,因为我们拥有RealmOptionalRealm Lists等的所有支持扩展。但是现在我不得不覆盖init(from decoder: Decoder)来手动对其进行解码,并且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)
}
Run Code Online (Sandbox Code Playgroud)
因此,有人可以向我建议使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
}
}
Run Code Online (Sandbox Code Playgroud)
然后,不要在学校类中使用 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
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,现在您使用的是 RealmNumeric 而不是 RealmOptional?这是 Optional 类型的。由于它是可选的,因此自动解码使用 decodeIfPresent 方法来解码可选值。如果它不存在于 json 中,则该值将简单地变为 nil。
| 归档时间: |
|
| 查看次数: |
1441 次 |
| 最近记录: |