使用 Decodable 解码 JSON 嵌套字典并使用 Core Data 存储它
Decoding JSON nested dictionary using Decodable and storing it using Core Data
我有以下 JSON
结构:
{
"base": "USD",
"date": "2020-04-24",
"rates": {
"CAD": 1.4049074074,
"EUR": 0.9259259259
}
}
我想将其解析为 class 并将其存储在 Core Data
:
class CurrencyRate: NSManagedObject, Decodable {
enum CodingKeys: String, CodingKey {
case base
case date
case rates
}
@NSManaged public var base: String
@NSManaged public var date: Date
@NSManaged public var rates: [String:Double]
required convenience init(from decoder: Decoder) throws {
...
}
根据我阅读的内容,为了在核心数据中存储 rates
字段,我必须创建另一个这样的实体并创建一对多关系:
class SubCurrencyRate: NSManagedObject, Decodable {
enum CodingKeys: String, CodingKey {
case currency
case rate
}
@NSManaged public var currency: String
@NSManaged public var rate: Double
required convenience init(from decoder: Decoder) throws {
...
}
CurrencyRate
class 中的字段 rates
将是:@NSManaged public var rates: [SubCurrencyRate]
问题是我不知道如何将带有动态键的嵌套 json 解析为这些 classes。怎么做到的?
以及一般情况下我如何解码 JSON 的这一部分:
"rates": {
"CAD": 1.4049074074,
"EUR": 0.9259259259
}
进入许多 SubCurrencyRate
个对象?
我前段时间写过一篇关于这个的文章blog post。
长话短说:我建议使用 DTO 解码为 CoreData 模型。考虑到 CoreData 模型总是绑定到一个上下文 - 从 JSON 解码时你没有 - 使用简单的结构来表示你的 JSON 然后从这些创建你的 CoreData 模型会更容易结构。
SubCurrencyRate
不一定要符合Decodable
,但你必须声明反向关系(也在数据模型中!)。
class SubCurrencyRate: NSManagedObject {
@NSManaged public var currency: String
@NSManaged public var rate: Double
@NSManaged public var currencyRate: CurrencyRate
为了能够在 Core Data 中直接解析 JSON 声明两个扩展
extension CodingUserInfoKey {
static let context = CodingUserInfoKey(rawValue: "context")!
}
extension JSONDecoder {
convenience init(context: NSManagedObjectContext) {
self.init()
self.userInfo[.context] = context
}
}
在CurrencyRate
中,您必须将对多关系声明为Set<SubCurrencyRate>
,在init(from decoder
中解码rates字典并将其映射到SubCurrencyRate
实例。如果模型中的关系定义正确,则会自动填充 属性 以及反向关系。
class CurrencyRate: NSManagedObject, Decodable {
enum CodingKeys: String, CodingKey { case base, date, rates }
@NSManaged public var base: String
@NSManaged public var date: Date
@NSManaged public var rates: Set<SubCurrencyRate>
required convenience init(from decoder: Decoder) throws {
guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Error: No object context!") }
let entity = NSEntityDescription.entity(forEntityName: "CurrencyRate", in: context)!
self.init(entity: entity, insertInto: context)
let values = try decoder.container(keyedBy: CodingKeys.self)
base = try values.decode(String.self, forKey: .base)
date = try values.decode(Date.self, forKey: .date)
let ratesData = try values.decode([String:Double].self, forKey: .rates)
for (key, value) in ratesData {
let subCurrencyRate = SubCurrencyRate(context: context)
subCurrencyRate.currency = key
subCurrencyRate.rate = value
subCurrencyRate.currencyRate = self
}
}
}
要解码 JSON 您必须在传递托管对象上下文的扩展中使用 JSONDecoder(context:
API 并正确解码 date
您必须添加一个合适的dateDecodingStrategy
.
我有以下 JSON
结构:
{
"base": "USD",
"date": "2020-04-24",
"rates": {
"CAD": 1.4049074074,
"EUR": 0.9259259259
}
}
我想将其解析为 class 并将其存储在 Core Data
:
class CurrencyRate: NSManagedObject, Decodable {
enum CodingKeys: String, CodingKey {
case base
case date
case rates
}
@NSManaged public var base: String
@NSManaged public var date: Date
@NSManaged public var rates: [String:Double]
required convenience init(from decoder: Decoder) throws {
...
}
根据我阅读的内容,为了在核心数据中存储 rates
字段,我必须创建另一个这样的实体并创建一对多关系:
class SubCurrencyRate: NSManagedObject, Decodable {
enum CodingKeys: String, CodingKey {
case currency
case rate
}
@NSManaged public var currency: String
@NSManaged public var rate: Double
required convenience init(from decoder: Decoder) throws {
...
}
CurrencyRate
class 中的字段 rates
将是:@NSManaged public var rates: [SubCurrencyRate]
问题是我不知道如何将带有动态键的嵌套 json 解析为这些 classes。怎么做到的?
以及一般情况下我如何解码 JSON 的这一部分:
"rates": {
"CAD": 1.4049074074,
"EUR": 0.9259259259
}
进入许多 SubCurrencyRate
个对象?
我前段时间写过一篇关于这个的文章blog post。 长话短说:我建议使用 DTO 解码为 CoreData 模型。考虑到 CoreData 模型总是绑定到一个上下文 - 从 JSON 解码时你没有 - 使用简单的结构来表示你的 JSON 然后从这些创建你的 CoreData 模型会更容易结构。
SubCurrencyRate
不一定要符合Decodable
,但你必须声明反向关系(也在数据模型中!)。
class SubCurrencyRate: NSManagedObject {
@NSManaged public var currency: String
@NSManaged public var rate: Double
@NSManaged public var currencyRate: CurrencyRate
为了能够在 Core Data 中直接解析 JSON 声明两个扩展
extension CodingUserInfoKey {
static let context = CodingUserInfoKey(rawValue: "context")!
}
extension JSONDecoder {
convenience init(context: NSManagedObjectContext) {
self.init()
self.userInfo[.context] = context
}
}
在CurrencyRate
中,您必须将对多关系声明为Set<SubCurrencyRate>
,在init(from decoder
中解码rates字典并将其映射到SubCurrencyRate
实例。如果模型中的关系定义正确,则会自动填充 属性 以及反向关系。
class CurrencyRate: NSManagedObject, Decodable {
enum CodingKeys: String, CodingKey { case base, date, rates }
@NSManaged public var base: String
@NSManaged public var date: Date
@NSManaged public var rates: Set<SubCurrencyRate>
required convenience init(from decoder: Decoder) throws {
guard let context = decoder.userInfo[.context] as? NSManagedObjectContext else { fatalError("Error: No object context!") }
let entity = NSEntityDescription.entity(forEntityName: "CurrencyRate", in: context)!
self.init(entity: entity, insertInto: context)
let values = try decoder.container(keyedBy: CodingKeys.self)
base = try values.decode(String.self, forKey: .base)
date = try values.decode(Date.self, forKey: .date)
let ratesData = try values.decode([String:Double].self, forKey: .rates)
for (key, value) in ratesData {
let subCurrencyRate = SubCurrencyRate(context: context)
subCurrencyRate.currency = key
subCurrencyRate.rate = value
subCurrencyRate.currencyRate = self
}
}
}
要解码 JSON 您必须在传递托管对象上下文的扩展中使用 JSONDecoder(context:
API 并正确解码 date
您必须添加一个合适的dateDecodingStrategy
.