一、问题
- 对于使用
HandyJson
或Codable
来解析的数据转成Realm
实例时失败!!! - 转成
Realm
实例时HandyJson
自定义映射无效!!!
二、解决方案
1. HandyJson
问题1:
let JsonString = """
{"genres":[{"id":28,"name":"Action"},{"id":12,"name":"Adventure"},{"id":16,"name":"Animation"},{"id":35,"name":"Comedy"},{"id":80,"name":"Crime"},{"id":99,"name":"Documentary"}]}
"""
class Genres: Object, HandyJSON {
@objc dynamic var id: String = ""
@objc dynamic var name: String?
override class func primaryKey() -> String? {
"id"
}
override required init() {
super.init()
}
}
let list: [Genres] = ([Genres].deserialize(from: JsonString, designatedPath: "genres") ?? []).compactMap { $0 }
list.forEach { print($0.id, $0.name) }
这里Realm
对象的属性不可使用@Persisted
标注,应该使用@objc dynamic
标注为OC
的动态类型。使用HandyJson
有个便捷之处是解析时可以直接将id
从Int
转成String
。
问题2:
这里有两种解决思路,直接上代码:
let JsonString = """
{"genres":[{"id":28,"name":"Action"},{"id":12,"name":"Adventure"},{"id":16,"name":"Animation"},{"id":35,"title":"Comedy"},{"id":80,"title":"Crime"},{"id":99,"title":"Documentary"}]}
"""
class Genres: Object, HandyJSON {
@objc dynamic var id: String = ""
@objc dynamic var name: String?
private var title: String?
override class func primaryKey() -> String? {
"id"
}
override required init() {
super.init()
}
/// 转换完成后赋值
func didFinishMapping() {
name = [name, title].compactMap { $0 }.first
}
}
let list: [Genres] = ([Genres].deserialize(from: JsonString, designatedPath: "genres") ?? []).compactMap { $0 }
list.forEach { print($0.id, $0.name) }
这种方式是在HandyJson
的didFinishMapping
中直接给属性赋值。再看另一种方式:
let JsonString = """
{"genres":[{"id":28,"name":"Action"},{"id":12,"name":"Adventure"},{"id":16,"name":"Animation"},{"id":35,"title":"Comedy"},{"id":80,"title":"Crime"},{"id":99,"title":"Documentary"}]}
"""
class Genres: Object, HandyJSON {
@objc dynamic var id: String = ""
@objc dynamic var name: String?
@objc private var title: String? {
willSet {
name = newValue
}
}
override class func ignoredProperties() -> [String] {
["title"]
}
override class func primaryKey() -> String? {
"id"
}
override required init() {
super.init()
}
}
let list: [Genres] = ([Genres].deserialize(from: JsonString, designatedPath: "genres") ?? []).compactMap { $0 }
list.forEach { print($0.id, $0.name) }
这里需要注意title
属性前面加了@objc
修饰表示这是OC
属性,这样HandyJson
在对title
赋值时willSet
将被调起,我们可以在willSet
中对name
进行赋值。如果不希望title
属性也存储到Realm
中,可以在Realm
的ignoredProperties
方法中标注。
执行代码后可以验证结果:
从Realm
的表结构可以看出,只有id
和name
,title
并不存在,其次name
的值也是完整的,这也符合我们的预期。
2. Codable
let JsonString = """
{"genres":[{"id":28,"name":"Action"},{"id":12,"name":"Adventure"},{"id":16,"name":"Animation"},{"id":35,"name":"Comedy"},{"id":80,"name":"Crime"},{"id":99,"name":"Documentary"}]}
"""
class GenresModel: Object, Codable {
@Persisted(primaryKey: true) var id: Int
@Persisted var name: String?
override required init() {
super.init()
}
}
let list = ([GenresModel].decodeJSON(from: JsonString, designatedPath: "genres") ?? []).compactMap { $0 }
list.forEach { print($0.id, $0.name) }
这里Realm
对象的属性可以使用@Persisted
标注。使用Codable
解析时需要注意匹配数据类型,不可以直接将id
从Int
转成String
,当然你也可以写映射方法来实现。